diff options
author | Tanner Gooding <tagoo@outlook.com> | 2018-02-03 14:32:27 -0800 |
---|---|---|
committer | Tanner Gooding <tagoo@outlook.com> | 2018-02-05 17:23:26 -0800 |
commit | 4578505a521bb4cbcf16d2361d87d24a9cacd25f (patch) | |
tree | 9ad895d95aafb1f7875a741ac7a9af4227e3f4f5 | |
parent | 691c7a0b0f1941a6186f4dbc1a04ccbc98d74c33 (diff) | |
download | coreclr-4578505a521bb4cbcf16d2361d87d24a9cacd25f.tar.gz coreclr-4578505a521bb4cbcf16d2361d87d24a9cacd25f.tar.bz2 coreclr-4578505a521bb4cbcf16d2361d87d24a9cacd25f.zip |
Moving a number of the Sse2 hwintrinsic tests to use the test template.
152 files changed, 25955 insertions, 3718 deletions
diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Shared/GenerateTests.csx b/tests/src/JIT/HardwareIntrinsics/X86/Shared/GenerateTests.csx index 5848273cc3..60bf0604c7 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Shared/GenerateTests.csx +++ b/tests/src/JIT/HardwareIntrinsics/X86/Shared/GenerateTests.csx @@ -77,16 +77,93 @@ private static readonly (string templateFileName, string[] templateData)[] SseIn private static readonly (string templateFileName, string[] templateData)[] Sse2Inputs = new [] { - // TemplateName Isa, LoadIsa, Method, BaseType, VectorType, VectorSize, NextValue, ValidateFirstResult, ValidateRemainingResults - ("SimpleBinOpTest.template", new string[] { "Sse2", "Sse2", "Add", "Double", "Vector128", "16", "(double)(random.NextDouble())", "BitConverter.DoubleToInt64Bits(left[0] + right[0]) != BitConverter.DoubleToInt64Bits(result[0])", "BitConverter.DoubleToInt64Bits(left[i] + right[i]) != BitConverter.DoubleToInt64Bits(result[i])"}), - ("SimpleBinOpTest.template", new string[] { "Sse2", "Sse2", "Add", "Byte", "Vector128", "16", "(byte)(random.Next(0, byte.MaxValue))", "(byte)(left[0] + right[0]) != result[0]", "(byte)(left[i] + right[i]) != result[i]"}), - ("SimpleBinOpTest.template", new string[] { "Sse2", "Sse2", "Add", "Int16", "Vector128", "16", "(short)(random.Next(short.MinValue, short.MaxValue))", "(short)(left[0] + right[0]) != result[0]", "(short)(left[i] + right[i]) != result[i]"}), - ("SimpleBinOpTest.template", new string[] { "Sse2", "Sse2", "Add", "Int32", "Vector128", "16", "(int)(random.Next(int.MinValue, int.MaxValue))", "(int)(left[0] + right[0]) != result[0]", "(int)(left[i] + right[i]) != result[i]"}), - ("SimpleBinOpTest.template", new string[] { "Sse2", "Sse2", "Add", "Int64", "Vector128", "16", "(long)(random.Next(int.MinValue, int.MaxValue))", "(long)(left[0] + right[0]) != result[0]", "(long)(left[i] + right[i]) != result[i]"}), - ("SimpleBinOpTest.template", new string[] { "Sse2", "Sse2", "Add", "SByte", "Vector128", "16", "(sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue))", "(sbyte)(left[0] + right[0]) != result[0]", "(sbyte)(left[i] + right[i]) != result[i]"}), - ("SimpleBinOpTest.template", new string[] { "Sse2", "Sse2", "Add", "UInt16", "Vector128", "16", "(ushort)(random.Next(0, ushort.MaxValue))", "(ushort)(left[0] + right[0]) != result[0]", "(ushort)(left[i] + right[i]) != result[i]"}), - ("SimpleBinOpTest.template", new string[] { "Sse2", "Sse2", "Add", "UInt32", "Vector128", "16", "(uint)(random.Next(0, int.MaxValue))", "(uint)(left[0] + right[0]) != result[0]", "(uint)(left[i] + right[i]) != result[i]"}), - ("SimpleBinOpTest.template", new string[] { "Sse2", "Sse2", "Add", "UInt64", "Vector128", "16", "(ulong)(random.Next(0, int.MaxValue))", "(ulong)(left[0] + right[0]) != result[0]", "(ulong)(left[i] + right[i]) != result[i]"}), + // TemplateName Isa, LoadIsa, Method, BaseType, VectorType, VectorSize, NextValue, ValidateFirstResult, ValidateRemainingResults + ("SimpleBinOpTest.template", new string[] { "Sse2", "Sse2", "Add", "Double", "Vector128", "16", "(double)(random.NextDouble())", "BitConverter.DoubleToInt64Bits(left[0] + right[0]) != BitConverter.DoubleToInt64Bits(result[0])", "BitConverter.DoubleToInt64Bits(left[i] + right[i]) != BitConverter.DoubleToInt64Bits(result[i])"}), + ("SimpleBinOpTest.template", new string[] { "Sse2", "Sse2", "Add", "Byte", "Vector128", "16", "(byte)(random.Next(0, byte.MaxValue))", "(byte)(left[0] + right[0]) != result[0]", "(byte)(left[i] + right[i]) != result[i]"}), + ("SimpleBinOpTest.template", new string[] { "Sse2", "Sse2", "Add", "Int16", "Vector128", "16", "(short)(random.Next(short.MinValue, short.MaxValue))", "(short)(left[0] + right[0]) != result[0]", "(short)(left[i] + right[i]) != result[i]"}), + ("SimpleBinOpTest.template", new string[] { "Sse2", "Sse2", "Add", "Int32", "Vector128", "16", "(int)(random.Next(int.MinValue, int.MaxValue))", "(int)(left[0] + right[0]) != result[0]", "(int)(left[i] + right[i]) != result[i]"}), + ("SimpleBinOpTest.template", new string[] { "Sse2", "Sse2", "Add", "Int64", "Vector128", "16", "(long)(random.Next(int.MinValue, int.MaxValue))", "(long)(left[0] + right[0]) != result[0]", "(long)(left[i] + right[i]) != result[i]"}), + ("SimpleBinOpTest.template", new string[] { "Sse2", "Sse2", "Add", "SByte", "Vector128", "16", "(sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue))", "(sbyte)(left[0] + right[0]) != result[0]", "(sbyte)(left[i] + right[i]) != result[i]"}), + ("SimpleBinOpTest.template", new string[] { "Sse2", "Sse2", "Add", "UInt16", "Vector128", "16", "(ushort)(random.Next(0, ushort.MaxValue))", "(ushort)(left[0] + right[0]) != result[0]", "(ushort)(left[i] + right[i]) != result[i]"}), + ("SimpleBinOpTest.template", new string[] { "Sse2", "Sse2", "Add", "UInt32", "Vector128", "16", "(uint)(random.Next(0, int.MaxValue))", "(uint)(left[0] + right[0]) != result[0]", "(uint)(left[i] + right[i]) != result[i]"}), + ("SimpleBinOpTest.template", new string[] { "Sse2", "Sse2", "Add", "UInt64", "Vector128", "16", "(ulong)(random.Next(0, int.MaxValue))", "(ulong)(left[0] + right[0]) != result[0]", "(ulong)(left[i] + right[i]) != result[i]"}), + ("SimpleBinOpTest.template", new string[] { "Sse2", "Sse2", "And", "Double", "Vector128", "16", "(double)(random.NextDouble())", "(BitConverter.DoubleToInt64Bits(left[0]) & BitConverter.DoubleToInt64Bits(right[0])) != BitConverter.DoubleToInt64Bits(result[0])", "(BitConverter.DoubleToInt64Bits(left[i]) & BitConverter.DoubleToInt64Bits(right[i])) != BitConverter.DoubleToInt64Bits(result[i])"}), + ("SimpleBinOpTest.template", new string[] { "Sse2", "Sse2", "And", "Byte", "Vector128", "16", "(byte)(random.Next(0, byte.MaxValue))", "(byte)(left[0] & right[0]) != result[0]", "(byte)(left[i] & right[i]) != result[i]"}), + ("SimpleBinOpTest.template", new string[] { "Sse2", "Sse2", "And", "Int16", "Vector128", "16", "(short)(random.Next(short.MinValue, short.MaxValue))", "(short)(left[0] & right[0]) != result[0]", "(short)(left[i] & right[i]) != result[i]"}), + ("SimpleBinOpTest.template", new string[] { "Sse2", "Sse2", "And", "Int32", "Vector128", "16", "(int)(random.Next(int.MinValue, int.MaxValue))", "(int)(left[0] & right[0]) != result[0]", "(int)(left[i] & right[i]) != result[i]"}), + ("SimpleBinOpTest.template", new string[] { "Sse2", "Sse2", "And", "Int64", "Vector128", "16", "(long)(random.Next(int.MinValue, int.MaxValue))", "(long)(left[0] & right[0]) != result[0]", "(long)(left[i] & right[i]) != result[i]"}), + ("SimpleBinOpTest.template", new string[] { "Sse2", "Sse2", "And", "SByte", "Vector128", "16", "(sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue))", "(sbyte)(left[0] & right[0]) != result[0]", "(sbyte)(left[i] & right[i]) != result[i]"}), + ("SimpleBinOpTest.template", new string[] { "Sse2", "Sse2", "And", "UInt16", "Vector128", "16", "(ushort)(random.Next(0, ushort.MaxValue))", "(ushort)(left[0] & right[0]) != result[0]", "(ushort)(left[i] & right[i]) != result[i]"}), + ("SimpleBinOpTest.template", new string[] { "Sse2", "Sse2", "And", "UInt32", "Vector128", "16", "(uint)(random.Next(0, int.MaxValue))", "(uint)(left[0] & right[0]) != result[0]", "(uint)(left[i] & right[i]) != result[i]"}), + ("SimpleBinOpTest.template", new string[] { "Sse2", "Sse2", "And", "UInt64", "Vector128", "16", "(ulong)(random.Next(0, int.MaxValue))", "(ulong)(left[0] & right[0]) != result[0]", "(ulong)(left[i] & right[i]) != result[i]"}), + ("SimpleBinOpTest.template", new string[] { "Sse2", "Sse2", "AndNot", "Double", "Vector128", "16", "(double)(random.NextDouble())", "(~BitConverter.DoubleToInt64Bits(left[0]) & BitConverter.DoubleToInt64Bits(right[0])) != BitConverter.DoubleToInt64Bits(result[0])", "(~BitConverter.DoubleToInt64Bits(left[i]) & BitConverter.DoubleToInt64Bits(right[i])) != BitConverter.DoubleToInt64Bits(result[i])"}), + ("SimpleBinOpTest.template", new string[] { "Sse2", "Sse2", "AndNot", "Byte", "Vector128", "16", "(byte)(random.Next(0, byte.MaxValue))", "(byte)(~left[0] & right[0]) != result[0]", "(byte)(~left[i] & right[i]) != result[i]"}), + ("SimpleBinOpTest.template", new string[] { "Sse2", "Sse2", "AndNot", "Int16", "Vector128", "16", "(short)(random.Next(short.MinValue, short.MaxValue))", "(short)(~left[0] & right[0]) != result[0]", "(short)(~left[i] & right[i]) != result[i]"}), + ("SimpleBinOpTest.template", new string[] { "Sse2", "Sse2", "AndNot", "Int32", "Vector128", "16", "(int)(random.Next(int.MinValue, int.MaxValue))", "(int)(~left[0] & right[0]) != result[0]", "(int)(~left[i] & right[i]) != result[i]"}), + ("SimpleBinOpTest.template", new string[] { "Sse2", "Sse2", "AndNot", "Int64", "Vector128", "16", "(long)(random.Next(int.MinValue, int.MaxValue))", "(long)(~left[0] & right[0]) != result[0]", "(long)(~left[i] & right[i]) != result[i]"}), + ("SimpleBinOpTest.template", new string[] { "Sse2", "Sse2", "AndNot", "SByte", "Vector128", "16", "(sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue))", "(sbyte)(~left[0] & right[0]) != result[0]", "(sbyte)(~left[i] & right[i]) != result[i]"}), + ("SimpleBinOpTest.template", new string[] { "Sse2", "Sse2", "AndNot", "UInt16", "Vector128", "16", "(ushort)(random.Next(0, ushort.MaxValue))", "(ushort)(~left[0] & right[0]) != result[0]", "(ushort)(~left[i] & right[i]) != result[i]"}), + ("SimpleBinOpTest.template", new string[] { "Sse2", "Sse2", "AndNot", "UInt32", "Vector128", "16", "(uint)(random.Next(0, int.MaxValue))", "(uint)(~left[0] & right[0]) != result[0]", "(uint)(~left[i] & right[i]) != result[i]"}), + ("SimpleBinOpTest.template", new string[] { "Sse2", "Sse2", "AndNot", "UInt64", "Vector128", "16", "(ulong)(random.Next(0, int.MaxValue))", "(ulong)(~left[0] & right[0]) != result[0]", "(ulong)(~left[i] & right[i]) != result[i]"}), + ("SimpleBinOpTest.template", new string[] { "Sse2", "Sse2", "CompareEqual", "Double", "Vector128", "16", "(double)(random.NextDouble())", "BitConverter.DoubleToInt64Bits(result[0]) != ((left[0] == right[0]) ? -1 : 0)", "BitConverter.DoubleToInt64Bits(result[i]) != ((left[i] == right[i]) ? -1 : 0)"}), + ("SimpleBinOpTest.template", new string[] { "Sse2", "Sse2", "CompareEqual", "Byte", "Vector128", "16", "(byte)(random.Next(0, byte.MaxValue))", "result[0] != ((left[0] == right[0]) ? unchecked((byte)(-1)) : 0)", "result[i] != ((left[i] == right[i]) ? unchecked((byte)(-1)) : 0)"}), + ("SimpleBinOpTest.template", new string[] { "Sse2", "Sse2", "CompareEqual", "Int16", "Vector128", "16", "(short)(random.Next(short.MinValue, short.MaxValue))", "result[0] != ((left[0] == right[0]) ? unchecked((short)(-1)) : 0)", "result[i] != ((left[i] == right[i]) ? unchecked((short)(-1)) : 0)"}), + ("SimpleBinOpTest.template", new string[] { "Sse2", "Sse2", "CompareEqual", "Int32", "Vector128", "16", "(int)(random.Next(int.MinValue, int.MaxValue))", "result[0] != ((left[0] == right[0]) ? unchecked((int)(-1)) : 0)", "result[i] != ((left[i] == right[i]) ? unchecked((int)(-1)) : 0)"}), + ("SimpleBinOpTest.template", new string[] { "Sse2", "Sse2", "CompareEqual", "SByte", "Vector128", "16", "(sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue))", "result[0] != ((left[0] == right[0]) ? unchecked((sbyte)(-1)) : 0)", "result[i] != ((left[i] == right[i]) ? unchecked((sbyte)(-1)) : 0)"}), + ("SimpleBinOpTest.template", new string[] { "Sse2", "Sse2", "CompareEqual", "UInt16", "Vector128", "16", "(ushort)(random.Next(0, ushort.MaxValue))", "result[0] != ((left[0] == right[0]) ? unchecked((ushort)(-1)) : 0)", "result[i] != ((left[i] == right[i]) ? unchecked((ushort)(-1)) : 0)"}), + ("SimpleBinOpTest.template", new string[] { "Sse2", "Sse2", "CompareEqual", "UInt32", "Vector128", "16", "(uint)(random.Next(0, int.MaxValue))", "result[0] != ((left[0] == right[0]) ? unchecked((uint)(-1)) : 0)", "result[i] != ((left[i] == right[i]) ? unchecked((uint)(-1)) : 0)"}), + ("SimpleBinOpTest.template", new string[] { "Sse2", "Sse2", "CompareGreaterThan", "Double", "Vector128", "16", "(double)(random.NextDouble())", "BitConverter.DoubleToInt64Bits(result[0]) != ((left[0] > right[0]) ? -1 : 0)", "BitConverter.DoubleToInt64Bits(result[i]) != ((left[i] > right[i]) ? -1 : 0)"}), + ("SimpleBinOpTest.template", new string[] { "Sse2", "Sse2", "CompareGreaterThan", "Int16", "Vector128", "16", "(short)(random.Next(short.MinValue, short.MaxValue))", "result[0] != ((left[0] > right[0]) ? unchecked((short)(-1)) : 0)", "result[i] != ((left[i] > right[i]) ? unchecked((short)(-1)) : 0)"}), + ("SimpleBinOpTest.template", new string[] { "Sse2", "Sse2", "CompareGreaterThan", "Int32", "Vector128", "16", "(int)(random.Next(int.MinValue, int.MaxValue))", "result[0] != ((left[0] > right[0]) ? unchecked((int)(-1)) : 0)", "result[i] != ((left[i] > right[i]) ? unchecked((int)(-1)) : 0)"}), + ("SimpleBinOpTest.template", new string[] { "Sse2", "Sse2", "CompareGreaterThan", "SByte", "Vector128", "16", "(sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue))", "result[0] != ((left[0] > right[0]) ? unchecked((sbyte)(-1)) : 0)", "result[i] != ((left[i] > right[i]) ? unchecked((sbyte)(-1)) : 0)"}), + ("SimpleBinOpTest.template", new string[] { "Sse2", "Sse2", "CompareGreaterThanOrEqual", "Double", "Vector128", "16", "(double)(random.NextDouble())", "BitConverter.DoubleToInt64Bits(result[0]) != ((left[0] >= right[0]) ? -1 : 0)", "BitConverter.DoubleToInt64Bits(result[i]) != ((left[i] >= right[i]) ? -1 : 0)"}), + ("SimpleBinOpTest.template", new string[] { "Sse2", "Sse2", "CompareLessThan", "Double", "Vector128", "16", "(double)(random.NextDouble())", "BitConverter.DoubleToInt64Bits(result[0]) != ((left[0] < right[0]) ? -1 : 0)", "BitConverter.DoubleToInt64Bits(result[i]) != ((left[i] < right[i]) ? -1 : 0)"}), + ("SimpleBinOpTest.template", new string[] { "Sse2", "Sse2", "CompareLessThan", "Int16", "Vector128", "16", "(short)(random.Next(short.MinValue, short.MaxValue))", "result[0] != ((left[0] < right[0]) ? unchecked((short)(-1)) : 0)", "result[i] != ((left[i] < right[i]) ? unchecked((short)(-1)) : 0)"}), + ("SimpleBinOpTest.template", new string[] { "Sse2", "Sse2", "CompareLessThan", "Int32", "Vector128", "16", "(int)(random.Next(int.MinValue, int.MaxValue))", "result[0] != ((left[0] < right[0]) ? unchecked((int)(-1)) : 0)", "result[i] != ((left[i] < right[i]) ? unchecked((int)(-1)) : 0)"}), + ("SimpleBinOpTest.template", new string[] { "Sse2", "Sse2", "CompareLessThan", "SByte", "Vector128", "16", "(sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue))", "result[0] != ((left[0] < right[0]) ? unchecked((sbyte)(-1)) : 0)", "result[i] != ((left[i] < right[i]) ? unchecked((sbyte)(-1)) : 0)"}), + ("SimpleBinOpTest.template", new string[] { "Sse2", "Sse2", "CompareLessThanOrEqual", "Double", "Vector128", "16", "(double)(random.NextDouble())", "BitConverter.DoubleToInt64Bits(result[0]) != ((left[0] <= right[0]) ? -1 : 0)", "BitConverter.DoubleToInt64Bits(result[i]) != ((left[i] <= right[i]) ? -1 : 0)"}), + ("SimpleBinOpTest.template", new string[] { "Sse2", "Sse2", "CompareNotEqual", "Double", "Vector128", "16", "(double)(random.NextDouble())", "BitConverter.DoubleToInt64Bits(result[0]) != ((left[0] != right[0]) ? -1 : 0)", "BitConverter.DoubleToInt64Bits(result[i]) != ((left[i] != right[i]) ? -1 : 0)"}), + ("SimpleBinOpTest.template", new string[] { "Sse2", "Sse2", "CompareNotGreaterThan", "Double", "Vector128", "16", "(double)(random.NextDouble())", "BitConverter.DoubleToInt64Bits(result[0]) != (!(left[0] > right[0]) ? -1 : 0)", "BitConverter.DoubleToInt64Bits(result[i]) != (!(left[i] > right[i]) ? -1 : 0)"}), + ("SimpleBinOpTest.template", new string[] { "Sse2", "Sse2", "CompareNotGreaterThanOrEqual", "Double", "Vector128", "16", "(double)(random.NextDouble())", "BitConverter.DoubleToInt64Bits(result[0]) != (!(left[0] >= right[0]) ? -1 : 0)", "BitConverter.DoubleToInt64Bits(result[i]) != (!(left[i] >= right[i]) ? -1 : 0)"}), + ("SimpleBinOpTest.template", new string[] { "Sse2", "Sse2", "CompareNotLessThan", "Double", "Vector128", "16", "(double)(random.NextDouble())", "BitConverter.DoubleToInt64Bits(result[0]) != (!(left[0] < right[0]) ? -1 : 0)", "BitConverter.DoubleToInt64Bits(result[i]) != (!(left[i] < right[i]) ? -1 : 0)"}), + ("SimpleBinOpTest.template", new string[] { "Sse2", "Sse2", "CompareNotLessThanOrEqual", "Double", "Vector128", "16", "(double)(random.NextDouble())", "BitConverter.DoubleToInt64Bits(result[0]) != (!(left[0] <= right[0]) ? -1 : 0)", "BitConverter.DoubleToInt64Bits(result[i]) != (!(left[i] <= right[i]) ? -1 : 0)"}), + ("SimpleBinOpTest.template", new string[] { "Sse2", "Sse2", "CompareOrdered", "Double", "Vector128", "16", "(double)(random.NextDouble())", "BitConverter.DoubleToInt64Bits(result[0]) != ((!double.IsNaN(left[0]) && !double.IsNaN(right[0])) ? -1 : 0)", "BitConverter.DoubleToInt64Bits(result[i]) != ((!double.IsNaN(left[i]) && !double.IsNaN(right[i])) ? -1 : 0)"}), + ("SimpleBinOpTest.template", new string[] { "Sse2", "Sse2", "CompareUnordered", "Double", "Vector128", "16", "(double)(random.NextDouble())", "BitConverter.DoubleToInt64Bits(result[0]) != ((double.IsNaN(left[0]) || double.IsNaN(right[0])) ? -1 : 0)", "BitConverter.DoubleToInt64Bits(result[i]) != ((double.IsNaN(left[i]) || double.IsNaN(right[i])) ? -1 : 0)"}), + ("SimpleBinOpTest.template", new string[] { "Sse2", "Sse2", "Divide", "Double", "Vector128", "16", "(double)(random.NextDouble())", "BitConverter.DoubleToInt64Bits(left[0] / right[0]) != BitConverter.DoubleToInt64Bits(result[0])", "BitConverter.DoubleToInt64Bits(left[i] / right[i]) != BitConverter.DoubleToInt64Bits(result[i])"}), + ("SimpleBinOpTest.template", new string[] { "Sse2", "Sse2", "Max", "Double", "Vector128", "16", "(double)(random.NextDouble())", "BitConverter.DoubleToInt64Bits(Math.Max(left[0], right[0])) != BitConverter.DoubleToInt64Bits(result[0])", "BitConverter.DoubleToInt64Bits(Math.Max(left[i], right[i])) != BitConverter.DoubleToInt64Bits(result[i])"}), + ("SimpleBinOpTest.template", new string[] { "Sse2", "Sse2", "Max", "Byte", "Vector128", "16", "(byte)(random.Next(0, byte.MaxValue))", "Math.Max(left[0], right[0]) != result[0]", "Math.Max(left[i], right[i]) != result[i]"}), + ("SimpleBinOpTest.template", new string[] { "Sse2", "Sse2", "Max", "Int16", "Vector128", "16", "(short)(random.Next(short.MinValue, short.MaxValue))", "Math.Max(left[0], right[0]) != result[0]", "Math.Max(left[i], right[i]) != result[i]"}), + ("SimpleBinOpTest.template", new string[] { "Sse2", "Sse2", "Min", "Double", "Vector128", "16", "(double)(random.NextDouble())", "BitConverter.DoubleToInt64Bits(Math.Min(left[0], right[0])) != BitConverter.DoubleToInt64Bits(result[0])", "BitConverter.DoubleToInt64Bits(Math.Min(left[i], right[i])) != BitConverter.DoubleToInt64Bits(result[i])"}), + ("SimpleBinOpTest.template", new string[] { "Sse2", "Sse2", "Min", "Byte", "Vector128", "16", "(byte)(random.Next(0, byte.MinValue))", "Math.Min(left[0], right[0]) != result[0]", "Math.Min(left[i], right[i]) != result[i]"}), + ("SimpleBinOpTest.template", new string[] { "Sse2", "Sse2", "Min", "Int16", "Vector128", "16", "(short)(random.Next(short.MinValue, short.MinValue))", "Math.Min(left[0], right[0]) != result[0]", "Math.Min(left[i], right[i]) != result[i]"}), + ("SimpleBinOpTest.template", new string[] { "Sse2", "Sse2", "Multiply", "Double", "Vector128", "16", "(double)(random.NextDouble())", "BitConverter.DoubleToInt64Bits(left[0] * right[0]) != BitConverter.DoubleToInt64Bits(result[0])", "BitConverter.DoubleToInt64Bits(left[i] * right[i]) != BitConverter.DoubleToInt64Bits(result[i])"}), + ("SimpleBinOpTest.template", new string[] { "Sse2", "Sse2", "Or", "Double", "Vector128", "16", "(double)(random.NextDouble())", "(BitConverter.DoubleToInt64Bits(left[0]) | BitConverter.DoubleToInt64Bits(right[0])) != BitConverter.DoubleToInt64Bits(result[0])", "(BitConverter.DoubleToInt64Bits(left[i]) | BitConverter.DoubleToInt64Bits(right[i])) != BitConverter.DoubleToInt64Bits(result[i])"}), + ("SimpleBinOpTest.template", new string[] { "Sse2", "Sse2", "Or", "Byte", "Vector128", "16", "(byte)(random.Next(0, byte.MaxValue))", "(byte)(left[0] | right[0]) != result[0]", "(byte)(left[i] | right[i]) != result[i]"}), + ("SimpleBinOpTest.template", new string[] { "Sse2", "Sse2", "Or", "Int16", "Vector128", "16", "(short)(random.Next(short.MinValue, short.MaxValue))", "(short)(left[0] | right[0]) != result[0]", "(short)(left[i] | right[i]) != result[i]"}), + ("SimpleBinOpTest.template", new string[] { "Sse2", "Sse2", "Or", "Int32", "Vector128", "16", "(int)(random.Next(int.MinValue, int.MaxValue))", "(int)(left[0] | right[0]) != result[0]", "(int)(left[i] | right[i]) != result[i]"}), + ("SimpleBinOpTest.template", new string[] { "Sse2", "Sse2", "Or", "Int64", "Vector128", "16", "(long)(random.Next(int.MinValue, int.MaxValue))", "(long)(left[0] | right[0]) != result[0]", "(long)(left[i] | right[i]) != result[i]"}), + ("SimpleBinOpTest.template", new string[] { "Sse2", "Sse2", "Or", "SByte", "Vector128", "16", "(sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue))", "(sbyte)(left[0] | right[0]) != result[0]", "(sbyte)(left[i] | right[i]) != result[i]"}), + ("SimpleBinOpTest.template", new string[] { "Sse2", "Sse2", "Or", "UInt16", "Vector128", "16", "(ushort)(random.Next(0, ushort.MaxValue))", "(ushort)(left[0] | right[0]) != result[0]", "(ushort)(left[i] | right[i]) != result[i]"}), + ("SimpleBinOpTest.template", new string[] { "Sse2", "Sse2", "Or", "UInt32", "Vector128", "16", "(uint)(random.Next(0, int.MaxValue))", "(uint)(left[0] | right[0]) != result[0]", "(uint)(left[i] | right[i]) != result[i]"}), + ("SimpleBinOpTest.template", new string[] { "Sse2", "Sse2", "Or", "UInt64", "Vector128", "16", "(ulong)(random.Next(0, int.MaxValue))", "(ulong)(left[0] | right[0]) != result[0]", "(ulong)(left[i] | right[i]) != result[i]"}), + ("SimpleBinOpTest.template", new string[] { "Sse2", "Sse2", "Subtract", "Double", "Vector128", "16", "(double)(random.NextDouble())", "BitConverter.DoubleToInt64Bits(left[0] - right[0]) != BitConverter.DoubleToInt64Bits(result[0])", "BitConverter.DoubleToInt64Bits(left[i] - right[i]) != BitConverter.DoubleToInt64Bits(result[i])"}), + ("SimpleBinOpTest.template", new string[] { "Sse2", "Sse2", "Subtract", "Byte", "Vector128", "16", "(byte)(random.Next(0, byte.MaxValue))", "(byte)(left[0] - right[0]) != result[0]", "(byte)(left[i] - right[i]) != result[i]"}), + ("SimpleBinOpTest.template", new string[] { "Sse2", "Sse2", "Subtract", "Int16", "Vector128", "16", "(short)(random.Next(short.MinValue, short.MaxValue))", "(short)(left[0] - right[0]) != result[0]", "(short)(left[i] - right[i]) != result[i]"}), + ("SimpleBinOpTest.template", new string[] { "Sse2", "Sse2", "Subtract", "Int32", "Vector128", "16", "(int)(random.Next(int.MinValue, int.MaxValue))", "(int)(left[0] - right[0]) != result[0]", "(int)(left[i] - right[i]) != result[i]"}), + ("SimpleBinOpTest.template", new string[] { "Sse2", "Sse2", "Subtract", "Int64", "Vector128", "16", "(long)(random.Next(int.MinValue, int.MaxValue))", "(long)(left[0] - right[0]) != result[0]", "(long)(left[i] - right[i]) != result[i]"}), + ("SimpleBinOpTest.template", new string[] { "Sse2", "Sse2", "Subtract", "SByte", "Vector128", "16", "(sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue))", "(sbyte)(left[0] - right[0]) != result[0]", "(sbyte)(left[i] - right[i]) != result[i]"}), + ("SimpleBinOpTest.template", new string[] { "Sse2", "Sse2", "Subtract", "UInt16", "Vector128", "16", "(ushort)(random.Next(0, ushort.MaxValue))", "(ushort)(left[0] - right[0]) != result[0]", "(ushort)(left[i] - right[i]) != result[i]"}), + ("SimpleBinOpTest.template", new string[] { "Sse2", "Sse2", "Subtract", "UInt32", "Vector128", "16", "(uint)(random.Next(0, int.MaxValue))", "(uint)(left[0] - right[0]) != result[0]", "(uint)(left[i] - right[i]) != result[i]"}), + ("SimpleBinOpTest.template", new string[] { "Sse2", "Sse2", "Subtract", "UInt64", "Vector128", "16", "(ulong)(random.Next(0, int.MaxValue))", "(ulong)(left[0] - right[0]) != result[0]", "(ulong)(left[i] - right[i]) != result[i]"}), + ("SimpleBinOpTest.template", new string[] { "Sse2", "Sse2", "Xor", "Double", "Vector128", "16", "(double)(random.NextDouble())", "(BitConverter.DoubleToInt64Bits(left[0]) ^ BitConverter.DoubleToInt64Bits(right[0])) != BitConverter.DoubleToInt64Bits(result[0])", "(BitConverter.DoubleToInt64Bits(left[i]) ^ BitConverter.DoubleToInt64Bits(right[i])) != BitConverter.DoubleToInt64Bits(result[i])"}), + ("SimpleBinOpTest.template", new string[] { "Sse2", "Sse2", "Xor", "Byte", "Vector128", "16", "(byte)(random.Next(0, byte.MaxValue))", "(byte)(left[0] ^ right[0]) != result[0]", "(byte)(left[i] ^ right[i]) != result[i]"}), + ("SimpleBinOpTest.template", new string[] { "Sse2", "Sse2", "Xor", "Int16", "Vector128", "16", "(short)(random.Next(short.MinValue, short.MaxValue))", "(short)(left[0] ^ right[0]) != result[0]", "(short)(left[i] ^ right[i]) != result[i]"}), + ("SimpleBinOpTest.template", new string[] { "Sse2", "Sse2", "Xor", "Int32", "Vector128", "16", "(int)(random.Next(int.MinValue, int.MaxValue))", "(int)(left[0] ^ right[0]) != result[0]", "(int)(left[i] ^ right[i]) != result[i]"}), + ("SimpleBinOpTest.template", new string[] { "Sse2", "Sse2", "Xor", "Int64", "Vector128", "16", "(long)(random.Next(int.MinValue, int.MaxValue))", "(long)(left[0] ^ right[0]) != result[0]", "(long)(left[i] ^ right[i]) != result[i]"}), + ("SimpleBinOpTest.template", new string[] { "Sse2", "Sse2", "Xor", "SByte", "Vector128", "16", "(sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue))", "(sbyte)(left[0] ^ right[0]) != result[0]", "(sbyte)(left[i] ^ right[i]) != result[i]"}), + ("SimpleBinOpTest.template", new string[] { "Sse2", "Sse2", "Xor", "UInt16", "Vector128", "16", "(ushort)(random.Next(0, ushort.MaxValue))", "(ushort)(left[0] ^ right[0]) != result[0]", "(ushort)(left[i] ^ right[i]) != result[i]"}), + ("SimpleBinOpTest.template", new string[] { "Sse2", "Sse2", "Xor", "UInt32", "Vector128", "16", "(uint)(random.Next(0, int.MaxValue))", "(uint)(left[0] ^ right[0]) != result[0]", "(uint)(left[i] ^ right[i]) != result[i]"}), + ("SimpleBinOpTest.template", new string[] { "Sse2", "Sse2", "Xor", "UInt64", "Vector128", "16", "(ulong)(random.Next(0, int.MaxValue))", "(ulong)(left[0] ^ right[0]) != result[0]", "(ulong)(left[i] ^ right[i]) != result[i]"}), }; private static readonly (string templateFileName, string[] templateData)[] AvxInputs = new [] @@ -163,8 +240,8 @@ private static void ProcessInput(StreamWriter testListFile, (string templateFile } ProcessInputs("Sse", SseInputs); +ProcessInputs("Sse2", Sse2Inputs); // TODO-XArch: Re-enable after the Load and LoadAligned intrinsics are implemented for SSE2 and AVX -// ProcessInputs("Sse2", Sse2Inputs); // ProcessInputs("Avx", AvxInputs); // ProcessInputs("Avx2", Avx2Inputs); diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Add.Byte.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Add.Byte.cs index 191101a046..fec58076dd 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Add.Byte.cs +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Add.Byte.cs @@ -25,17 +25,35 @@ namespace JIT.HardwareIntrinsics.X86 if (test.IsSupported) { - // Validates basic functionality works - test.RunBasicScenario(); + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); - // Validates calling via reflection works - test.RunReflectionScenario(); + // 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(); + + // 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 - test.RunLclVarScenario(); + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + // 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 works test.RunLclFldScenario(); @@ -92,14 +110,14 @@ namespace JIT.HardwareIntrinsics.X86 Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Byte>, byte>(ref _fld2), ref Unsafe.As<Byte, byte>(ref _data2[0]), VectorSize); for (var i = 0; i < ElementCount; i++) { _data1[i] = (byte)(random.Next(0, byte.MaxValue)); _data2[i] = (byte)(random.Next(0, byte.MaxValue)); } - _dataTable = new SimpleBinaryOpTest__DataTable<Byte>(_data1, _data2, new Byte[ElementCount]); + _dataTable = new SimpleBinaryOpTest__DataTable<Byte>(_data1, _data2, new Byte[ElementCount], VectorSize); } public bool IsSupported => Sse2.IsSupported; public bool Succeeded { get; set; } - public void RunBasicScenario() + public void RunBasicScenario_UnsafeRead() { var result = Sse2.Add( Unsafe.Read<Vector128<Byte>>(_dataTable.inArray1Ptr), @@ -107,10 +125,32 @@ namespace JIT.HardwareIntrinsics.X86 ); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse2.Add( + Sse2.LoadVector128((Byte*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Byte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse2.Add( + Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); } - public void RunReflectionScenario() + public void RunReflectionScenario_UnsafeRead() { var result = typeof(Sse2).GetMethod(nameof(Sse2.Add), new Type[] { typeof(Vector128<Byte>), typeof(Vector128<Byte>) }) .Invoke(null, new object[] { @@ -119,7 +159,31 @@ namespace JIT.HardwareIntrinsics.X86 }); Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Byte>)(result)); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Add), new Type[] { typeof(Vector128<Byte>), typeof(Vector128<Byte>) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Byte*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Byte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Byte>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Add), new Type[] { typeof(Vector128<Byte>), typeof(Vector128<Byte>) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Byte>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); } public void RunClsVarScenario() @@ -130,17 +194,37 @@ namespace JIT.HardwareIntrinsics.X86 ); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_clsVar1, _clsVar2, _dataTable.outArray); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); } - public void RunLclVarScenario() + public void RunLclVarScenario_UnsafeRead() { var left = Unsafe.Read<Vector128<Byte>>(_dataTable.inArray1Ptr); var right = Unsafe.Read<Vector128<Byte>>(_dataTable.inArray2Ptr); var result = Sse2.Add(left, right); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(left, right, _dataTable.outArray); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((Byte*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((Byte*)(_dataTable.inArray2Ptr)); + var result = Sse2.Add(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray2Ptr)); + var result = Sse2.Add(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); } public void RunLclFldScenario() @@ -149,7 +233,7 @@ namespace JIT.HardwareIntrinsics.X86 var result = Sse2.Add(test._fld1, test._fld2); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(test._fld1, test._fld2, _dataTable.outArray); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); } public void RunFldScenario() @@ -157,7 +241,7 @@ namespace JIT.HardwareIntrinsics.X86 var result = Sse2.Add(_fld1, _fld2); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_fld1, _fld2, _dataTable.outArray); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); } public void RunUnsupportedScenario() @@ -166,7 +250,7 @@ namespace JIT.HardwareIntrinsics.X86 try { - RunBasicScenario(); + RunBasicScenario_UnsafeRead(); } catch (PlatformNotSupportedException) { @@ -174,15 +258,30 @@ namespace JIT.HardwareIntrinsics.X86 } } - private void ValidateResult(Vector128<Byte> left, Vector128<Byte> right, Byte[] result, [CallerMemberName] string method = "") + private void ValidateResult(Vector128<Byte> left, Vector128<Byte> right, void* result, [CallerMemberName] string method = "") { Byte[] inArray1 = new Byte[ElementCount]; Byte[] inArray2 = new Byte[ElementCount]; + Byte[] outArray = new Byte[ElementCount]; Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Byte, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[ElementCount]; + Byte[] inArray2 = new Byte[ElementCount]; + Byte[] outArray = new Byte[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Byte, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Byte, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Byte, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); - ValidateResult(inArray1, inArray2, result, method); + ValidateResult(inArray1, inArray2, outArray, method); } private void ValidateResult(Byte[] left, Byte[] right, Byte[] result, [CallerMemberName] string method = "") diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Add.Double.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Add.Double.cs index 63eb9250a0..a6a2d771ee 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Add.Double.cs +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Add.Double.cs @@ -25,17 +25,35 @@ namespace JIT.HardwareIntrinsics.X86 if (test.IsSupported) { - // Validates basic functionality works - test.RunBasicScenario(); + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); - // Validates calling via reflection works - test.RunReflectionScenario(); + // 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(); + + // 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 - test.RunLclVarScenario(); + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + // 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 works test.RunLclFldScenario(); @@ -92,14 +110,14 @@ namespace JIT.HardwareIntrinsics.X86 Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Double>, byte>(ref _fld2), ref Unsafe.As<Double, byte>(ref _data2[0]), VectorSize); for (var i = 0; i < ElementCount; i++) { _data1[i] = (double)(random.NextDouble()); _data2[i] = (double)(random.NextDouble()); } - _dataTable = new SimpleBinaryOpTest__DataTable<Double>(_data1, _data2, new Double[ElementCount]); + _dataTable = new SimpleBinaryOpTest__DataTable<Double>(_data1, _data2, new Double[ElementCount], VectorSize); } public bool IsSupported => Sse2.IsSupported; public bool Succeeded { get; set; } - public void RunBasicScenario() + public void RunBasicScenario_UnsafeRead() { var result = Sse2.Add( Unsafe.Read<Vector128<Double>>(_dataTable.inArray1Ptr), @@ -107,10 +125,32 @@ namespace JIT.HardwareIntrinsics.X86 ); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse2.Add( + Sse2.LoadVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Double*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse2.Add( + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); } - public void RunReflectionScenario() + public void RunReflectionScenario_UnsafeRead() { var result = typeof(Sse2).GetMethod(nameof(Sse2.Add), new Type[] { typeof(Vector128<Double>), typeof(Vector128<Double>) }) .Invoke(null, new object[] { @@ -119,7 +159,31 @@ namespace JIT.HardwareIntrinsics.X86 }); Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Double>)(result)); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Add), new Type[] { typeof(Vector128<Double>), typeof(Vector128<Double>) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Double*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Double>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Add), new Type[] { typeof(Vector128<Double>), typeof(Vector128<Double>) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Double>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); } public void RunClsVarScenario() @@ -130,17 +194,37 @@ namespace JIT.HardwareIntrinsics.X86 ); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_clsVar1, _clsVar2, _dataTable.outArray); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); } - public void RunLclVarScenario() + public void RunLclVarScenario_UnsafeRead() { var left = Unsafe.Read<Vector128<Double>>(_dataTable.inArray1Ptr); var right = Unsafe.Read<Vector128<Double>>(_dataTable.inArray2Ptr); var result = Sse2.Add(left, right); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(left, right, _dataTable.outArray); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((Double*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((Double*)(_dataTable.inArray2Ptr)); + var result = Sse2.Add(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray2Ptr)); + var result = Sse2.Add(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); } public void RunLclFldScenario() @@ -149,7 +233,7 @@ namespace JIT.HardwareIntrinsics.X86 var result = Sse2.Add(test._fld1, test._fld2); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(test._fld1, test._fld2, _dataTable.outArray); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); } public void RunFldScenario() @@ -157,7 +241,7 @@ namespace JIT.HardwareIntrinsics.X86 var result = Sse2.Add(_fld1, _fld2); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_fld1, _fld2, _dataTable.outArray); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); } public void RunUnsupportedScenario() @@ -166,7 +250,7 @@ namespace JIT.HardwareIntrinsics.X86 try { - RunBasicScenario(); + RunBasicScenario_UnsafeRead(); } catch (PlatformNotSupportedException) { @@ -174,15 +258,30 @@ namespace JIT.HardwareIntrinsics.X86 } } - private void ValidateResult(Vector128<Double> left, Vector128<Double> right, Double[] result, [CallerMemberName] string method = "") + private void ValidateResult(Vector128<Double> left, Vector128<Double> right, void* result, [CallerMemberName] string method = "") { Double[] inArray1 = new Double[ElementCount]; Double[] inArray2 = new Double[ElementCount]; + Double[] outArray = new Double[ElementCount]; Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Double[] inArray1 = new Double[ElementCount]; + Double[] inArray2 = new Double[ElementCount]; + Double[] outArray = new Double[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); - ValidateResult(inArray1, inArray2, result, method); + ValidateResult(inArray1, inArray2, outArray, method); } private void ValidateResult(Double[] left, Double[] right, Double[] result, [CallerMemberName] string method = "") diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Add.Int16.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Add.Int16.cs index 78aae6eb43..a4e17a627f 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Add.Int16.cs +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Add.Int16.cs @@ -25,17 +25,35 @@ namespace JIT.HardwareIntrinsics.X86 if (test.IsSupported) { - // Validates basic functionality works - test.RunBasicScenario(); + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); - // Validates calling via reflection works - test.RunReflectionScenario(); + // 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(); + + // 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 - test.RunLclVarScenario(); + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + // 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 works test.RunLclFldScenario(); @@ -92,14 +110,14 @@ namespace JIT.HardwareIntrinsics.X86 Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int16>, byte>(ref _fld2), ref Unsafe.As<Int16, byte>(ref _data2[0]), VectorSize); for (var i = 0; i < ElementCount; i++) { _data1[i] = (short)(random.Next(short.MinValue, short.MaxValue)); _data2[i] = (short)(random.Next(short.MinValue, short.MaxValue)); } - _dataTable = new SimpleBinaryOpTest__DataTable<Int16>(_data1, _data2, new Int16[ElementCount]); + _dataTable = new SimpleBinaryOpTest__DataTable<Int16>(_data1, _data2, new Int16[ElementCount], VectorSize); } public bool IsSupported => Sse2.IsSupported; public bool Succeeded { get; set; } - public void RunBasicScenario() + public void RunBasicScenario_UnsafeRead() { var result = Sse2.Add( Unsafe.Read<Vector128<Int16>>(_dataTable.inArray1Ptr), @@ -107,10 +125,32 @@ namespace JIT.HardwareIntrinsics.X86 ); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse2.Add( + Sse2.LoadVector128((Int16*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Int16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse2.Add( + Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); } - public void RunReflectionScenario() + public void RunReflectionScenario_UnsafeRead() { var result = typeof(Sse2).GetMethod(nameof(Sse2.Add), new Type[] { typeof(Vector128<Int16>), typeof(Vector128<Int16>) }) .Invoke(null, new object[] { @@ -119,7 +159,31 @@ namespace JIT.HardwareIntrinsics.X86 }); Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Int16>)(result)); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Add), new Type[] { typeof(Vector128<Int16>), typeof(Vector128<Int16>) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Int16*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Int16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Int16>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Add), new Type[] { typeof(Vector128<Int16>), typeof(Vector128<Int16>) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Int16>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); } public void RunClsVarScenario() @@ -130,17 +194,37 @@ namespace JIT.HardwareIntrinsics.X86 ); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_clsVar1, _clsVar2, _dataTable.outArray); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); } - public void RunLclVarScenario() + public void RunLclVarScenario_UnsafeRead() { var left = Unsafe.Read<Vector128<Int16>>(_dataTable.inArray1Ptr); var right = Unsafe.Read<Vector128<Int16>>(_dataTable.inArray2Ptr); var result = Sse2.Add(left, right); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(left, right, _dataTable.outArray); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((Int16*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((Int16*)(_dataTable.inArray2Ptr)); + var result = Sse2.Add(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray2Ptr)); + var result = Sse2.Add(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); } public void RunLclFldScenario() @@ -149,7 +233,7 @@ namespace JIT.HardwareIntrinsics.X86 var result = Sse2.Add(test._fld1, test._fld2); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(test._fld1, test._fld2, _dataTable.outArray); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); } public void RunFldScenario() @@ -157,7 +241,7 @@ namespace JIT.HardwareIntrinsics.X86 var result = Sse2.Add(_fld1, _fld2); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_fld1, _fld2, _dataTable.outArray); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); } public void RunUnsupportedScenario() @@ -166,7 +250,7 @@ namespace JIT.HardwareIntrinsics.X86 try { - RunBasicScenario(); + RunBasicScenario_UnsafeRead(); } catch (PlatformNotSupportedException) { @@ -174,15 +258,30 @@ namespace JIT.HardwareIntrinsics.X86 } } - private void ValidateResult(Vector128<Int16> left, Vector128<Int16> right, Int16[] result, [CallerMemberName] string method = "") + private void ValidateResult(Vector128<Int16> left, Vector128<Int16> right, void* result, [CallerMemberName] string method = "") { Int16[] inArray1 = new Int16[ElementCount]; Int16[] inArray2 = new Int16[ElementCount]; + Int16[] outArray = new Int16[ElementCount]; Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int16, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[ElementCount]; + Int16[] inArray2 = new Int16[ElementCount]; + Int16[] outArray = new Int16[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int16, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int16, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int16, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); - ValidateResult(inArray1, inArray2, result, method); + ValidateResult(inArray1, inArray2, outArray, method); } private void ValidateResult(Int16[] left, Int16[] right, Int16[] result, [CallerMemberName] string method = "") diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Add.Int32.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Add.Int32.cs index 9bd209494d..2b6916f82b 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Add.Int32.cs +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Add.Int32.cs @@ -25,17 +25,35 @@ namespace JIT.HardwareIntrinsics.X86 if (test.IsSupported) { - // Validates basic functionality works - test.RunBasicScenario(); + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); - // Validates calling via reflection works - test.RunReflectionScenario(); + // 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(); + + // 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 - test.RunLclVarScenario(); + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + // 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 works test.RunLclFldScenario(); @@ -92,14 +110,14 @@ namespace JIT.HardwareIntrinsics.X86 Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int32>, byte>(ref _fld2), ref Unsafe.As<Int32, byte>(ref _data2[0]), VectorSize); for (var i = 0; i < ElementCount; i++) { _data1[i] = (int)(random.Next(int.MinValue, int.MaxValue)); _data2[i] = (int)(random.Next(int.MinValue, int.MaxValue)); } - _dataTable = new SimpleBinaryOpTest__DataTable<Int32>(_data1, _data2, new Int32[ElementCount]); + _dataTable = new SimpleBinaryOpTest__DataTable<Int32>(_data1, _data2, new Int32[ElementCount], VectorSize); } public bool IsSupported => Sse2.IsSupported; public bool Succeeded { get; set; } - public void RunBasicScenario() + public void RunBasicScenario_UnsafeRead() { var result = Sse2.Add( Unsafe.Read<Vector128<Int32>>(_dataTable.inArray1Ptr), @@ -107,10 +125,32 @@ namespace JIT.HardwareIntrinsics.X86 ); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse2.Add( + Sse2.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Int32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse2.Add( + Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); } - public void RunReflectionScenario() + public void RunReflectionScenario_UnsafeRead() { var result = typeof(Sse2).GetMethod(nameof(Sse2.Add), new Type[] { typeof(Vector128<Int32>), typeof(Vector128<Int32>) }) .Invoke(null, new object[] { @@ -119,7 +159,31 @@ namespace JIT.HardwareIntrinsics.X86 }); Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Int32>)(result)); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Add), new Type[] { typeof(Vector128<Int32>), typeof(Vector128<Int32>) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Int32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Int32>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Add), new Type[] { typeof(Vector128<Int32>), typeof(Vector128<Int32>) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Int32>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); } public void RunClsVarScenario() @@ -130,17 +194,37 @@ namespace JIT.HardwareIntrinsics.X86 ); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_clsVar1, _clsVar2, _dataTable.outArray); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); } - public void RunLclVarScenario() + public void RunLclVarScenario_UnsafeRead() { var left = Unsafe.Read<Vector128<Int32>>(_dataTable.inArray1Ptr); var right = Unsafe.Read<Vector128<Int32>>(_dataTable.inArray2Ptr); var result = Sse2.Add(left, right); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(left, right, _dataTable.outArray); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((Int32*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((Int32*)(_dataTable.inArray2Ptr)); + var result = Sse2.Add(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray2Ptr)); + var result = Sse2.Add(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); } public void RunLclFldScenario() @@ -149,7 +233,7 @@ namespace JIT.HardwareIntrinsics.X86 var result = Sse2.Add(test._fld1, test._fld2); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(test._fld1, test._fld2, _dataTable.outArray); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); } public void RunFldScenario() @@ -157,7 +241,7 @@ namespace JIT.HardwareIntrinsics.X86 var result = Sse2.Add(_fld1, _fld2); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_fld1, _fld2, _dataTable.outArray); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); } public void RunUnsupportedScenario() @@ -166,7 +250,7 @@ namespace JIT.HardwareIntrinsics.X86 try { - RunBasicScenario(); + RunBasicScenario_UnsafeRead(); } catch (PlatformNotSupportedException) { @@ -174,15 +258,30 @@ namespace JIT.HardwareIntrinsics.X86 } } - private void ValidateResult(Vector128<Int32> left, Vector128<Int32> right, Int32[] result, [CallerMemberName] string method = "") + private void ValidateResult(Vector128<Int32> left, Vector128<Int32> right, void* result, [CallerMemberName] string method = "") { Int32[] inArray1 = new Int32[ElementCount]; Int32[] inArray2 = new Int32[ElementCount]; + Int32[] outArray = new Int32[ElementCount]; Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int32, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[ElementCount]; + Int32[] inArray2 = new Int32[ElementCount]; + Int32[] outArray = new Int32[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int32, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int32, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int32, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); - ValidateResult(inArray1, inArray2, result, method); + ValidateResult(inArray1, inArray2, outArray, method); } private void ValidateResult(Int32[] left, Int32[] right, Int32[] result, [CallerMemberName] string method = "") diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Add.Int64.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Add.Int64.cs index 1d0e18e1fb..09812f4270 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Add.Int64.cs +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Add.Int64.cs @@ -25,17 +25,35 @@ namespace JIT.HardwareIntrinsics.X86 if (test.IsSupported) { - // Validates basic functionality works - test.RunBasicScenario(); + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); - // Validates calling via reflection works - test.RunReflectionScenario(); + // 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(); + + // 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 - test.RunLclVarScenario(); + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + // 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 works test.RunLclFldScenario(); @@ -92,14 +110,14 @@ namespace JIT.HardwareIntrinsics.X86 Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int64>, byte>(ref _fld2), ref Unsafe.As<Int64, byte>(ref _data2[0]), VectorSize); for (var i = 0; i < ElementCount; i++) { _data1[i] = (long)(random.Next(int.MinValue, int.MaxValue)); _data2[i] = (long)(random.Next(int.MinValue, int.MaxValue)); } - _dataTable = new SimpleBinaryOpTest__DataTable<Int64>(_data1, _data2, new Int64[ElementCount]); + _dataTable = new SimpleBinaryOpTest__DataTable<Int64>(_data1, _data2, new Int64[ElementCount], VectorSize); } public bool IsSupported => Sse2.IsSupported; public bool Succeeded { get; set; } - public void RunBasicScenario() + public void RunBasicScenario_UnsafeRead() { var result = Sse2.Add( Unsafe.Read<Vector128<Int64>>(_dataTable.inArray1Ptr), @@ -107,10 +125,32 @@ namespace JIT.HardwareIntrinsics.X86 ); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse2.Add( + Sse2.LoadVector128((Int64*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Int64*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse2.Add( + Sse2.LoadAlignedVector128((Int64*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Int64*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); } - public void RunReflectionScenario() + public void RunReflectionScenario_UnsafeRead() { var result = typeof(Sse2).GetMethod(nameof(Sse2.Add), new Type[] { typeof(Vector128<Int64>), typeof(Vector128<Int64>) }) .Invoke(null, new object[] { @@ -119,7 +159,31 @@ namespace JIT.HardwareIntrinsics.X86 }); Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Int64>)(result)); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Add), new Type[] { typeof(Vector128<Int64>), typeof(Vector128<Int64>) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Int64*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Int64*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Int64>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Add), new Type[] { typeof(Vector128<Int64>), typeof(Vector128<Int64>) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Int64*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Int64*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Int64>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); } public void RunClsVarScenario() @@ -130,17 +194,37 @@ namespace JIT.HardwareIntrinsics.X86 ); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_clsVar1, _clsVar2, _dataTable.outArray); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); } - public void RunLclVarScenario() + public void RunLclVarScenario_UnsafeRead() { var left = Unsafe.Read<Vector128<Int64>>(_dataTable.inArray1Ptr); var right = Unsafe.Read<Vector128<Int64>>(_dataTable.inArray2Ptr); var result = Sse2.Add(left, right); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(left, right, _dataTable.outArray); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((Int64*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((Int64*)(_dataTable.inArray2Ptr)); + var result = Sse2.Add(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((Int64*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((Int64*)(_dataTable.inArray2Ptr)); + var result = Sse2.Add(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); } public void RunLclFldScenario() @@ -149,7 +233,7 @@ namespace JIT.HardwareIntrinsics.X86 var result = Sse2.Add(test._fld1, test._fld2); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(test._fld1, test._fld2, _dataTable.outArray); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); } public void RunFldScenario() @@ -157,7 +241,7 @@ namespace JIT.HardwareIntrinsics.X86 var result = Sse2.Add(_fld1, _fld2); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_fld1, _fld2, _dataTable.outArray); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); } public void RunUnsupportedScenario() @@ -166,7 +250,7 @@ namespace JIT.HardwareIntrinsics.X86 try { - RunBasicScenario(); + RunBasicScenario_UnsafeRead(); } catch (PlatformNotSupportedException) { @@ -174,15 +258,30 @@ namespace JIT.HardwareIntrinsics.X86 } } - private void ValidateResult(Vector128<Int64> left, Vector128<Int64> right, Int64[] result, [CallerMemberName] string method = "") + private void ValidateResult(Vector128<Int64> left, Vector128<Int64> right, void* result, [CallerMemberName] string method = "") { Int64[] inArray1 = new Int64[ElementCount]; Int64[] inArray2 = new Int64[ElementCount]; + Int64[] outArray = new Int64[ElementCount]; Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int64, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[ElementCount]; + Int64[] inArray2 = new Int64[ElementCount]; + Int64[] outArray = new Int64[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int64, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int64, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int64, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); - ValidateResult(inArray1, inArray2, result, method); + ValidateResult(inArray1, inArray2, outArray, method); } private void ValidateResult(Int64[] left, Int64[] right, Int64[] result, [CallerMemberName] string method = "") diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Add.SByte.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Add.SByte.cs index e496ae47e1..6db15f6a8f 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Add.SByte.cs +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Add.SByte.cs @@ -25,17 +25,35 @@ namespace JIT.HardwareIntrinsics.X86 if (test.IsSupported) { - // Validates basic functionality works - test.RunBasicScenario(); + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); - // Validates calling via reflection works - test.RunReflectionScenario(); + // 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(); + + // 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 - test.RunLclVarScenario(); + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + // 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 works test.RunLclFldScenario(); @@ -92,14 +110,14 @@ namespace JIT.HardwareIntrinsics.X86 Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<SByte>, byte>(ref _fld2), ref Unsafe.As<SByte, byte>(ref _data2[0]), VectorSize); for (var i = 0; i < ElementCount; i++) { _data1[i] = (sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue)); _data2[i] = (sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue)); } - _dataTable = new SimpleBinaryOpTest__DataTable<SByte>(_data1, _data2, new SByte[ElementCount]); + _dataTable = new SimpleBinaryOpTest__DataTable<SByte>(_data1, _data2, new SByte[ElementCount], VectorSize); } public bool IsSupported => Sse2.IsSupported; public bool Succeeded { get; set; } - public void RunBasicScenario() + public void RunBasicScenario_UnsafeRead() { var result = Sse2.Add( Unsafe.Read<Vector128<SByte>>(_dataTable.inArray1Ptr), @@ -107,10 +125,32 @@ namespace JIT.HardwareIntrinsics.X86 ); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse2.Add( + Sse2.LoadVector128((SByte*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((SByte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse2.Add( + Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); } - public void RunReflectionScenario() + public void RunReflectionScenario_UnsafeRead() { var result = typeof(Sse2).GetMethod(nameof(Sse2.Add), new Type[] { typeof(Vector128<SByte>), typeof(Vector128<SByte>) }) .Invoke(null, new object[] { @@ -119,7 +159,31 @@ namespace JIT.HardwareIntrinsics.X86 }); Unsafe.Write(_dataTable.outArrayPtr, (Vector128<SByte>)(result)); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Add), new Type[] { typeof(Vector128<SByte>), typeof(Vector128<SByte>) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((SByte*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((SByte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<SByte>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Add), new Type[] { typeof(Vector128<SByte>), typeof(Vector128<SByte>) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<SByte>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); } public void RunClsVarScenario() @@ -130,17 +194,37 @@ namespace JIT.HardwareIntrinsics.X86 ); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_clsVar1, _clsVar2, _dataTable.outArray); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); } - public void RunLclVarScenario() + public void RunLclVarScenario_UnsafeRead() { var left = Unsafe.Read<Vector128<SByte>>(_dataTable.inArray1Ptr); var right = Unsafe.Read<Vector128<SByte>>(_dataTable.inArray2Ptr); var result = Sse2.Add(left, right); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(left, right, _dataTable.outArray); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((SByte*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((SByte*)(_dataTable.inArray2Ptr)); + var result = Sse2.Add(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArray2Ptr)); + var result = Sse2.Add(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); } public void RunLclFldScenario() @@ -149,7 +233,7 @@ namespace JIT.HardwareIntrinsics.X86 var result = Sse2.Add(test._fld1, test._fld2); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(test._fld1, test._fld2, _dataTable.outArray); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); } public void RunFldScenario() @@ -157,7 +241,7 @@ namespace JIT.HardwareIntrinsics.X86 var result = Sse2.Add(_fld1, _fld2); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_fld1, _fld2, _dataTable.outArray); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); } public void RunUnsupportedScenario() @@ -166,7 +250,7 @@ namespace JIT.HardwareIntrinsics.X86 try { - RunBasicScenario(); + RunBasicScenario_UnsafeRead(); } catch (PlatformNotSupportedException) { @@ -174,15 +258,30 @@ namespace JIT.HardwareIntrinsics.X86 } } - private void ValidateResult(Vector128<SByte> left, Vector128<SByte> right, SByte[] result, [CallerMemberName] string method = "") + private void ValidateResult(Vector128<SByte> left, Vector128<SByte> right, void* result, [CallerMemberName] string method = "") { SByte[] inArray1 = new SByte[ElementCount]; SByte[] inArray2 = new SByte[ElementCount]; + SByte[] outArray = new SByte[ElementCount]; Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<SByte, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[ElementCount]; + SByte[] inArray2 = new SByte[ElementCount]; + SByte[] outArray = new SByte[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<SByte, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<SByte, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<SByte, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); - ValidateResult(inArray1, inArray2, result, method); + ValidateResult(inArray1, inArray2, outArray, method); } private void ValidateResult(SByte[] left, SByte[] right, SByte[] result, [CallerMemberName] string method = "") diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Add.UInt16.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Add.UInt16.cs index 549c99f219..b26b1dc64d 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Add.UInt16.cs +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Add.UInt16.cs @@ -25,17 +25,35 @@ namespace JIT.HardwareIntrinsics.X86 if (test.IsSupported) { - // Validates basic functionality works - test.RunBasicScenario(); + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); - // Validates calling via reflection works - test.RunReflectionScenario(); + // 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(); + + // 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 - test.RunLclVarScenario(); + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + // 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 works test.RunLclFldScenario(); @@ -92,14 +110,14 @@ namespace JIT.HardwareIntrinsics.X86 Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt16>, byte>(ref _fld2), ref Unsafe.As<UInt16, byte>(ref _data2[0]), VectorSize); for (var i = 0; i < ElementCount; i++) { _data1[i] = (ushort)(random.Next(0, ushort.MaxValue)); _data2[i] = (ushort)(random.Next(0, ushort.MaxValue)); } - _dataTable = new SimpleBinaryOpTest__DataTable<UInt16>(_data1, _data2, new UInt16[ElementCount]); + _dataTable = new SimpleBinaryOpTest__DataTable<UInt16>(_data1, _data2, new UInt16[ElementCount], VectorSize); } public bool IsSupported => Sse2.IsSupported; public bool Succeeded { get; set; } - public void RunBasicScenario() + public void RunBasicScenario_UnsafeRead() { var result = Sse2.Add( Unsafe.Read<Vector128<UInt16>>(_dataTable.inArray1Ptr), @@ -107,10 +125,32 @@ namespace JIT.HardwareIntrinsics.X86 ); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse2.Add( + Sse2.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse2.Add( + Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); } - public void RunReflectionScenario() + public void RunReflectionScenario_UnsafeRead() { var result = typeof(Sse2).GetMethod(nameof(Sse2.Add), new Type[] { typeof(Vector128<UInt16>), typeof(Vector128<UInt16>) }) .Invoke(null, new object[] { @@ -119,7 +159,31 @@ namespace JIT.HardwareIntrinsics.X86 }); Unsafe.Write(_dataTable.outArrayPtr, (Vector128<UInt16>)(result)); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Add), new Type[] { typeof(Vector128<UInt16>), typeof(Vector128<UInt16>) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<UInt16>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Add), new Type[] { typeof(Vector128<UInt16>), typeof(Vector128<UInt16>) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<UInt16>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); } public void RunClsVarScenario() @@ -130,17 +194,37 @@ namespace JIT.HardwareIntrinsics.X86 ); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_clsVar1, _clsVar2, _dataTable.outArray); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); } - public void RunLclVarScenario() + public void RunLclVarScenario_UnsafeRead() { var left = Unsafe.Read<Vector128<UInt16>>(_dataTable.inArray1Ptr); var right = Unsafe.Read<Vector128<UInt16>>(_dataTable.inArray2Ptr); var result = Sse2.Add(left, right); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(left, right, _dataTable.outArray); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)); + var result = Sse2.Add(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArray2Ptr)); + var result = Sse2.Add(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); } public void RunLclFldScenario() @@ -149,7 +233,7 @@ namespace JIT.HardwareIntrinsics.X86 var result = Sse2.Add(test._fld1, test._fld2); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(test._fld1, test._fld2, _dataTable.outArray); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); } public void RunFldScenario() @@ -157,7 +241,7 @@ namespace JIT.HardwareIntrinsics.X86 var result = Sse2.Add(_fld1, _fld2); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_fld1, _fld2, _dataTable.outArray); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); } public void RunUnsupportedScenario() @@ -166,7 +250,7 @@ namespace JIT.HardwareIntrinsics.X86 try { - RunBasicScenario(); + RunBasicScenario_UnsafeRead(); } catch (PlatformNotSupportedException) { @@ -174,15 +258,30 @@ namespace JIT.HardwareIntrinsics.X86 } } - private void ValidateResult(Vector128<UInt16> left, Vector128<UInt16> right, UInt16[] result, [CallerMemberName] string method = "") + private void ValidateResult(Vector128<UInt16> left, Vector128<UInt16> right, void* result, [CallerMemberName] string method = "") { UInt16[] inArray1 = new UInt16[ElementCount]; UInt16[] inArray2 = new UInt16[ElementCount]; + UInt16[] outArray = new UInt16[ElementCount]; Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt16, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[ElementCount]; + UInt16[] inArray2 = new UInt16[ElementCount]; + UInt16[] outArray = new UInt16[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt16, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt16, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt16, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); - ValidateResult(inArray1, inArray2, result, method); + ValidateResult(inArray1, inArray2, outArray, method); } private void ValidateResult(UInt16[] left, UInt16[] right, UInt16[] result, [CallerMemberName] string method = "") diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Add.UInt32.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Add.UInt32.cs index 7e94c2f133..753093a392 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Add.UInt32.cs +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Add.UInt32.cs @@ -25,17 +25,35 @@ namespace JIT.HardwareIntrinsics.X86 if (test.IsSupported) { - // Validates basic functionality works - test.RunBasicScenario(); + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); - // Validates calling via reflection works - test.RunReflectionScenario(); + // 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(); + + // 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 - test.RunLclVarScenario(); + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + // 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 works test.RunLclFldScenario(); @@ -92,14 +110,14 @@ namespace JIT.HardwareIntrinsics.X86 Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt32>, byte>(ref _fld2), ref Unsafe.As<UInt32, byte>(ref _data2[0]), VectorSize); for (var i = 0; i < ElementCount; i++) { _data1[i] = (uint)(random.Next(0, int.MaxValue)); _data2[i] = (uint)(random.Next(0, int.MaxValue)); } - _dataTable = new SimpleBinaryOpTest__DataTable<UInt32>(_data1, _data2, new UInt32[ElementCount]); + _dataTable = new SimpleBinaryOpTest__DataTable<UInt32>(_data1, _data2, new UInt32[ElementCount], VectorSize); } public bool IsSupported => Sse2.IsSupported; public bool Succeeded { get; set; } - public void RunBasicScenario() + public void RunBasicScenario_UnsafeRead() { var result = Sse2.Add( Unsafe.Read<Vector128<UInt32>>(_dataTable.inArray1Ptr), @@ -107,10 +125,32 @@ namespace JIT.HardwareIntrinsics.X86 ); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse2.Add( + Sse2.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse2.Add( + Sse2.LoadAlignedVector128((UInt32*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((UInt32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); } - public void RunReflectionScenario() + public void RunReflectionScenario_UnsafeRead() { var result = typeof(Sse2).GetMethod(nameof(Sse2.Add), new Type[] { typeof(Vector128<UInt32>), typeof(Vector128<UInt32>) }) .Invoke(null, new object[] { @@ -119,7 +159,31 @@ namespace JIT.HardwareIntrinsics.X86 }); Unsafe.Write(_dataTable.outArrayPtr, (Vector128<UInt32>)(result)); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Add), new Type[] { typeof(Vector128<UInt32>), typeof(Vector128<UInt32>) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<UInt32>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Add), new Type[] { typeof(Vector128<UInt32>), typeof(Vector128<UInt32>) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((UInt32*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((UInt32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<UInt32>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); } public void RunClsVarScenario() @@ -130,17 +194,37 @@ namespace JIT.HardwareIntrinsics.X86 ); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_clsVar1, _clsVar2, _dataTable.outArray); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); } - public void RunLclVarScenario() + public void RunLclVarScenario_UnsafeRead() { var left = Unsafe.Read<Vector128<UInt32>>(_dataTable.inArray1Ptr); var right = Unsafe.Read<Vector128<UInt32>>(_dataTable.inArray2Ptr); var result = Sse2.Add(left, right); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(left, right, _dataTable.outArray); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)); + var result = Sse2.Add(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((UInt32*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((UInt32*)(_dataTable.inArray2Ptr)); + var result = Sse2.Add(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); } public void RunLclFldScenario() @@ -149,7 +233,7 @@ namespace JIT.HardwareIntrinsics.X86 var result = Sse2.Add(test._fld1, test._fld2); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(test._fld1, test._fld2, _dataTable.outArray); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); } public void RunFldScenario() @@ -157,7 +241,7 @@ namespace JIT.HardwareIntrinsics.X86 var result = Sse2.Add(_fld1, _fld2); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_fld1, _fld2, _dataTable.outArray); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); } public void RunUnsupportedScenario() @@ -166,7 +250,7 @@ namespace JIT.HardwareIntrinsics.X86 try { - RunBasicScenario(); + RunBasicScenario_UnsafeRead(); } catch (PlatformNotSupportedException) { @@ -174,15 +258,30 @@ namespace JIT.HardwareIntrinsics.X86 } } - private void ValidateResult(Vector128<UInt32> left, Vector128<UInt32> right, UInt32[] result, [CallerMemberName] string method = "") + private void ValidateResult(Vector128<UInt32> left, Vector128<UInt32> right, void* result, [CallerMemberName] string method = "") { UInt32[] inArray1 = new UInt32[ElementCount]; UInt32[] inArray2 = new UInt32[ElementCount]; + UInt32[] outArray = new UInt32[ElementCount]; Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt32, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[ElementCount]; + UInt32[] inArray2 = new UInt32[ElementCount]; + UInt32[] outArray = new UInt32[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt32, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt32, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt32, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); - ValidateResult(inArray1, inArray2, result, method); + ValidateResult(inArray1, inArray2, outArray, method); } private void ValidateResult(UInt32[] left, UInt32[] right, UInt32[] result, [CallerMemberName] string method = "") diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Add.UInt64.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Add.UInt64.cs index efc23590cd..23ee721995 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Add.UInt64.cs +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Add.UInt64.cs @@ -25,17 +25,35 @@ namespace JIT.HardwareIntrinsics.X86 if (test.IsSupported) { - // Validates basic functionality works - test.RunBasicScenario(); + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); - // Validates calling via reflection works - test.RunReflectionScenario(); + // 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(); + + // 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 - test.RunLclVarScenario(); + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + // 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 works test.RunLclFldScenario(); @@ -92,14 +110,14 @@ namespace JIT.HardwareIntrinsics.X86 Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt64>, byte>(ref _fld2), ref Unsafe.As<UInt64, byte>(ref _data2[0]), VectorSize); for (var i = 0; i < ElementCount; i++) { _data1[i] = (ulong)(random.Next(0, int.MaxValue)); _data2[i] = (ulong)(random.Next(0, int.MaxValue)); } - _dataTable = new SimpleBinaryOpTest__DataTable<UInt64>(_data1, _data2, new UInt64[ElementCount]); + _dataTable = new SimpleBinaryOpTest__DataTable<UInt64>(_data1, _data2, new UInt64[ElementCount], VectorSize); } public bool IsSupported => Sse2.IsSupported; public bool Succeeded { get; set; } - public void RunBasicScenario() + public void RunBasicScenario_UnsafeRead() { var result = Sse2.Add( Unsafe.Read<Vector128<UInt64>>(_dataTable.inArray1Ptr), @@ -107,10 +125,32 @@ namespace JIT.HardwareIntrinsics.X86 ); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse2.Add( + Sse2.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((UInt64*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse2.Add( + Sse2.LoadAlignedVector128((UInt64*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((UInt64*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); } - public void RunReflectionScenario() + public void RunReflectionScenario_UnsafeRead() { var result = typeof(Sse2).GetMethod(nameof(Sse2.Add), new Type[] { typeof(Vector128<UInt64>), typeof(Vector128<UInt64>) }) .Invoke(null, new object[] { @@ -119,7 +159,31 @@ namespace JIT.HardwareIntrinsics.X86 }); Unsafe.Write(_dataTable.outArrayPtr, (Vector128<UInt64>)(result)); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Add), new Type[] { typeof(Vector128<UInt64>), typeof(Vector128<UInt64>) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((UInt64*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<UInt64>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Add), new Type[] { typeof(Vector128<UInt64>), typeof(Vector128<UInt64>) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((UInt64*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((UInt64*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<UInt64>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); } public void RunClsVarScenario() @@ -130,17 +194,37 @@ namespace JIT.HardwareIntrinsics.X86 ); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_clsVar1, _clsVar2, _dataTable.outArray); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); } - public void RunLclVarScenario() + public void RunLclVarScenario_UnsafeRead() { var left = Unsafe.Read<Vector128<UInt64>>(_dataTable.inArray1Ptr); var right = Unsafe.Read<Vector128<UInt64>>(_dataTable.inArray2Ptr); var result = Sse2.Add(left, right); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(left, right, _dataTable.outArray); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((UInt64*)(_dataTable.inArray2Ptr)); + var result = Sse2.Add(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((UInt64*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((UInt64*)(_dataTable.inArray2Ptr)); + var result = Sse2.Add(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); } public void RunLclFldScenario() @@ -149,7 +233,7 @@ namespace JIT.HardwareIntrinsics.X86 var result = Sse2.Add(test._fld1, test._fld2); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(test._fld1, test._fld2, _dataTable.outArray); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); } public void RunFldScenario() @@ -157,7 +241,7 @@ namespace JIT.HardwareIntrinsics.X86 var result = Sse2.Add(_fld1, _fld2); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_fld1, _fld2, _dataTable.outArray); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); } public void RunUnsupportedScenario() @@ -166,7 +250,7 @@ namespace JIT.HardwareIntrinsics.X86 try { - RunBasicScenario(); + RunBasicScenario_UnsafeRead(); } catch (PlatformNotSupportedException) { @@ -174,15 +258,30 @@ namespace JIT.HardwareIntrinsics.X86 } } - private void ValidateResult(Vector128<UInt64> left, Vector128<UInt64> right, UInt64[] result, [CallerMemberName] string method = "") + private void ValidateResult(Vector128<UInt64> left, Vector128<UInt64> right, void* result, [CallerMemberName] string method = "") { UInt64[] inArray1 = new UInt64[ElementCount]; UInt64[] inArray2 = new UInt64[ElementCount]; + UInt64[] outArray = new UInt64[ElementCount]; Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt64, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray1 = new UInt64[ElementCount]; + UInt64[] inArray2 = new UInt64[ElementCount]; + UInt64[] outArray = new UInt64[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt64, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt64, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt64, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); - ValidateResult(inArray1, inArray2, result, method); + ValidateResult(inArray1, inArray2, outArray, method); } private void ValidateResult(UInt64[] left, UInt64[] right, UInt64[] result, [CallerMemberName] string method = "") diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/And.Byte.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/And.Byte.cs new file mode 100644 index 0000000000..9841e66e57 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/And.Byte.cs @@ -0,0 +1,315 @@ +// 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 AndByte() + { + var test = new SimpleBinaryOpTest__AndByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + // 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(); + + // 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(); + + // 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 works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + 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__AndByte + { + private const int VectorSize = 16; + private const int ElementCount = VectorSize / sizeof(Byte); + + private static Byte[] _data1 = new Byte[ElementCount]; + private static Byte[] _data2 = new Byte[ElementCount]; + + private static Vector128<Byte> _clsVar1; + private static Vector128<Byte> _clsVar2; + + private Vector128<Byte> _fld1; + private Vector128<Byte> _fld2; + + private SimpleBinaryOpTest__DataTable<Byte> _dataTable; + + static SimpleBinaryOpTest__AndByte() + { + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (byte)(random.Next(0, byte.MaxValue)); _data2[i] = (byte)(random.Next(0, byte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Byte>, byte>(ref _clsVar1), ref Unsafe.As<Byte, byte>(ref _data2[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Byte>, byte>(ref _clsVar2), ref Unsafe.As<Byte, byte>(ref _data1[0]), VectorSize); + } + + public SimpleBinaryOpTest__AndByte() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (byte)(random.Next(0, byte.MaxValue)); _data2[i] = (byte)(random.Next(0, byte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Byte>, byte>(ref _fld1), ref Unsafe.As<Byte, byte>(ref _data1[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Byte>, byte>(ref _fld2), ref Unsafe.As<Byte, byte>(ref _data2[0]), VectorSize); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (byte)(random.Next(0, byte.MaxValue)); _data2[i] = (byte)(random.Next(0, byte.MaxValue)); } + _dataTable = new SimpleBinaryOpTest__DataTable<Byte>(_data1, _data2, new Byte[ElementCount], VectorSize); + } + + public bool IsSupported => Sse2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse2.And( + Unsafe.Read<Vector128<Byte>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<Byte>>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse2.And( + Sse2.LoadVector128((Byte*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Byte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse2.And( + Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.And), new Type[] { typeof(Vector128<Byte>), typeof(Vector128<Byte>) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector128<Byte>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<Byte>>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Byte>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.And), new Type[] { typeof(Vector128<Byte>), typeof(Vector128<Byte>) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Byte*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Byte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Byte>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.And), new Type[] { typeof(Vector128<Byte>), typeof(Vector128<Byte>) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Byte>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse2.And( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read<Vector128<Byte>>(_dataTable.inArray1Ptr); + var right = Unsafe.Read<Vector128<Byte>>(_dataTable.inArray2Ptr); + var result = Sse2.And(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((Byte*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((Byte*)(_dataTable.inArray2Ptr)); + var result = Sse2.And(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray2Ptr)); + var result = Sse2.And(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__AndByte(); + var result = Sse2.And(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse2.And(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128<Byte> left, Vector128<Byte> right, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[ElementCount]; + Byte[] inArray2 = new Byte[ElementCount]; + Byte[] outArray = new Byte[ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Byte, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[ElementCount]; + Byte[] inArray2 = new Byte[ElementCount]; + Byte[] outArray = new Byte[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Byte, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Byte, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Byte, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Byte[] left, Byte[] right, Byte[] result, [CallerMemberName] string method = "") + { + if ((byte)(left[0] & right[0]) != result[0]) + { + Succeeded = false; + } + else + { + for (var i = 1; i < left.Length; i++) + { + if ((byte)(left[i] & right[i]) != result[i]) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Sse2)}.{nameof(Sse2.And)}<Byte>: {method} failed:"); + Console.WriteLine($" left: ({string.Join(", ", left)})"); + Console.WriteLine($" right: ({string.Join(", ", right)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/And.Double.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/And.Double.cs new file mode 100644 index 0000000000..2f6f0d79c6 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/And.Double.cs @@ -0,0 +1,315 @@ +// 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 AndDouble() + { + var test = new SimpleBinaryOpTest__AndDouble(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + // 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(); + + // 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(); + + // 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 works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + 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__AndDouble + { + private const int VectorSize = 16; + private const int ElementCount = VectorSize / sizeof(Double); + + private static Double[] _data1 = new Double[ElementCount]; + private static Double[] _data2 = new Double[ElementCount]; + + private static Vector128<Double> _clsVar1; + private static Vector128<Double> _clsVar2; + + private Vector128<Double> _fld1; + private Vector128<Double> _fld2; + + private SimpleBinaryOpTest__DataTable<Double> _dataTable; + + static SimpleBinaryOpTest__AndDouble() + { + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (double)(random.NextDouble()); _data2[i] = (double)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Double>, byte>(ref _clsVar1), ref Unsafe.As<Double, byte>(ref _data2[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Double>, byte>(ref _clsVar2), ref Unsafe.As<Double, byte>(ref _data1[0]), VectorSize); + } + + public SimpleBinaryOpTest__AndDouble() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (double)(random.NextDouble()); _data2[i] = (double)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Double>, byte>(ref _fld1), ref Unsafe.As<Double, byte>(ref _data1[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Double>, byte>(ref _fld2), ref Unsafe.As<Double, byte>(ref _data2[0]), VectorSize); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (double)(random.NextDouble()); _data2[i] = (double)(random.NextDouble()); } + _dataTable = new SimpleBinaryOpTest__DataTable<Double>(_data1, _data2, new Double[ElementCount], VectorSize); + } + + public bool IsSupported => Sse2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse2.And( + Unsafe.Read<Vector128<Double>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<Double>>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse2.And( + Sse2.LoadVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Double*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse2.And( + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.And), new Type[] { typeof(Vector128<Double>), typeof(Vector128<Double>) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector128<Double>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<Double>>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Double>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.And), new Type[] { typeof(Vector128<Double>), typeof(Vector128<Double>) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Double*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Double>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.And), new Type[] { typeof(Vector128<Double>), typeof(Vector128<Double>) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Double>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse2.And( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read<Vector128<Double>>(_dataTable.inArray1Ptr); + var right = Unsafe.Read<Vector128<Double>>(_dataTable.inArray2Ptr); + var result = Sse2.And(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((Double*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((Double*)(_dataTable.inArray2Ptr)); + var result = Sse2.And(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray2Ptr)); + var result = Sse2.And(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__AndDouble(); + var result = Sse2.And(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse2.And(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128<Double> left, Vector128<Double> right, void* result, [CallerMemberName] string method = "") + { + Double[] inArray1 = new Double[ElementCount]; + Double[] inArray2 = new Double[ElementCount]; + Double[] outArray = new Double[ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Double[] inArray1 = new Double[ElementCount]; + Double[] inArray2 = new Double[ElementCount]; + Double[] outArray = new Double[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Double[] left, Double[] right, Double[] result, [CallerMemberName] string method = "") + { + if ((BitConverter.DoubleToInt64Bits(left[0]) & BitConverter.DoubleToInt64Bits(right[0])) != BitConverter.DoubleToInt64Bits(result[0])) + { + Succeeded = false; + } + else + { + for (var i = 1; i < left.Length; i++) + { + if ((BitConverter.DoubleToInt64Bits(left[i]) & BitConverter.DoubleToInt64Bits(right[i])) != BitConverter.DoubleToInt64Bits(result[i])) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Sse2)}.{nameof(Sse2.And)}<Double>: {method} failed:"); + Console.WriteLine($" left: ({string.Join(", ", left)})"); + Console.WriteLine($" right: ({string.Join(", ", right)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/And.Int16.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/And.Int16.cs new file mode 100644 index 0000000000..d5c18eeaf5 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/And.Int16.cs @@ -0,0 +1,315 @@ +// 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 AndInt16() + { + var test = new SimpleBinaryOpTest__AndInt16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + // 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(); + + // 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(); + + // 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 works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + 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__AndInt16 + { + private const int VectorSize = 16; + private const int ElementCount = VectorSize / sizeof(Int16); + + private static Int16[] _data1 = new Int16[ElementCount]; + private static Int16[] _data2 = new Int16[ElementCount]; + + private static Vector128<Int16> _clsVar1; + private static Vector128<Int16> _clsVar2; + + private Vector128<Int16> _fld1; + private Vector128<Int16> _fld2; + + private SimpleBinaryOpTest__DataTable<Int16> _dataTable; + + static SimpleBinaryOpTest__AndInt16() + { + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (short)(random.Next(short.MinValue, short.MaxValue)); _data2[i] = (short)(random.Next(short.MinValue, short.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int16>, byte>(ref _clsVar1), ref Unsafe.As<Int16, byte>(ref _data2[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int16>, byte>(ref _clsVar2), ref Unsafe.As<Int16, byte>(ref _data1[0]), VectorSize); + } + + public SimpleBinaryOpTest__AndInt16() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (short)(random.Next(short.MinValue, short.MaxValue)); _data2[i] = (short)(random.Next(short.MinValue, short.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int16>, byte>(ref _fld1), ref Unsafe.As<Int16, byte>(ref _data1[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int16>, byte>(ref _fld2), ref Unsafe.As<Int16, byte>(ref _data2[0]), VectorSize); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (short)(random.Next(short.MinValue, short.MaxValue)); _data2[i] = (short)(random.Next(short.MinValue, short.MaxValue)); } + _dataTable = new SimpleBinaryOpTest__DataTable<Int16>(_data1, _data2, new Int16[ElementCount], VectorSize); + } + + public bool IsSupported => Sse2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse2.And( + Unsafe.Read<Vector128<Int16>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<Int16>>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse2.And( + Sse2.LoadVector128((Int16*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Int16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse2.And( + Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.And), new Type[] { typeof(Vector128<Int16>), typeof(Vector128<Int16>) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector128<Int16>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<Int16>>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Int16>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.And), new Type[] { typeof(Vector128<Int16>), typeof(Vector128<Int16>) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Int16*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Int16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Int16>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.And), new Type[] { typeof(Vector128<Int16>), typeof(Vector128<Int16>) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Int16>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse2.And( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read<Vector128<Int16>>(_dataTable.inArray1Ptr); + var right = Unsafe.Read<Vector128<Int16>>(_dataTable.inArray2Ptr); + var result = Sse2.And(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((Int16*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((Int16*)(_dataTable.inArray2Ptr)); + var result = Sse2.And(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray2Ptr)); + var result = Sse2.And(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__AndInt16(); + var result = Sse2.And(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse2.And(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128<Int16> left, Vector128<Int16> right, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[ElementCount]; + Int16[] inArray2 = new Int16[ElementCount]; + Int16[] outArray = new Int16[ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int16, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[ElementCount]; + Int16[] inArray2 = new Int16[ElementCount]; + Int16[] outArray = new Int16[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int16, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int16, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int16, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int16[] left, Int16[] right, Int16[] result, [CallerMemberName] string method = "") + { + if ((short)(left[0] & right[0]) != result[0]) + { + Succeeded = false; + } + else + { + for (var i = 1; i < left.Length; i++) + { + if ((short)(left[i] & right[i]) != result[i]) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Sse2)}.{nameof(Sse2.And)}<Int16>: {method} failed:"); + Console.WriteLine($" left: ({string.Join(", ", left)})"); + Console.WriteLine($" right: ({string.Join(", ", right)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/And.Int32.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/And.Int32.cs new file mode 100644 index 0000000000..f440ef540c --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/And.Int32.cs @@ -0,0 +1,315 @@ +// 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 AndInt32() + { + var test = new SimpleBinaryOpTest__AndInt32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + // 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(); + + // 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(); + + // 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 works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + 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__AndInt32 + { + private const int VectorSize = 16; + private const int ElementCount = VectorSize / sizeof(Int32); + + private static Int32[] _data1 = new Int32[ElementCount]; + private static Int32[] _data2 = new Int32[ElementCount]; + + private static Vector128<Int32> _clsVar1; + private static Vector128<Int32> _clsVar2; + + private Vector128<Int32> _fld1; + private Vector128<Int32> _fld2; + + private SimpleBinaryOpTest__DataTable<Int32> _dataTable; + + static SimpleBinaryOpTest__AndInt32() + { + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (int)(random.Next(int.MinValue, int.MaxValue)); _data2[i] = (int)(random.Next(int.MinValue, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int32>, byte>(ref _clsVar1), ref Unsafe.As<Int32, byte>(ref _data2[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int32>, byte>(ref _clsVar2), ref Unsafe.As<Int32, byte>(ref _data1[0]), VectorSize); + } + + public SimpleBinaryOpTest__AndInt32() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (int)(random.Next(int.MinValue, int.MaxValue)); _data2[i] = (int)(random.Next(int.MinValue, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int32>, byte>(ref _fld1), ref Unsafe.As<Int32, byte>(ref _data1[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int32>, byte>(ref _fld2), ref Unsafe.As<Int32, byte>(ref _data2[0]), VectorSize); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (int)(random.Next(int.MinValue, int.MaxValue)); _data2[i] = (int)(random.Next(int.MinValue, int.MaxValue)); } + _dataTable = new SimpleBinaryOpTest__DataTable<Int32>(_data1, _data2, new Int32[ElementCount], VectorSize); + } + + public bool IsSupported => Sse2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse2.And( + Unsafe.Read<Vector128<Int32>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<Int32>>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse2.And( + Sse2.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Int32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse2.And( + Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.And), new Type[] { typeof(Vector128<Int32>), typeof(Vector128<Int32>) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector128<Int32>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<Int32>>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Int32>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.And), new Type[] { typeof(Vector128<Int32>), typeof(Vector128<Int32>) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Int32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Int32>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.And), new Type[] { typeof(Vector128<Int32>), typeof(Vector128<Int32>) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Int32>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse2.And( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read<Vector128<Int32>>(_dataTable.inArray1Ptr); + var right = Unsafe.Read<Vector128<Int32>>(_dataTable.inArray2Ptr); + var result = Sse2.And(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((Int32*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((Int32*)(_dataTable.inArray2Ptr)); + var result = Sse2.And(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray2Ptr)); + var result = Sse2.And(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__AndInt32(); + var result = Sse2.And(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse2.And(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128<Int32> left, Vector128<Int32> right, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[ElementCount]; + Int32[] inArray2 = new Int32[ElementCount]; + Int32[] outArray = new Int32[ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int32, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[ElementCount]; + Int32[] inArray2 = new Int32[ElementCount]; + Int32[] outArray = new Int32[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int32, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int32, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int32, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int32[] left, Int32[] right, Int32[] result, [CallerMemberName] string method = "") + { + if ((int)(left[0] & right[0]) != result[0]) + { + Succeeded = false; + } + else + { + for (var i = 1; i < left.Length; i++) + { + if ((int)(left[i] & right[i]) != result[i]) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Sse2)}.{nameof(Sse2.And)}<Int32>: {method} failed:"); + Console.WriteLine($" left: ({string.Join(", ", left)})"); + Console.WriteLine($" right: ({string.Join(", ", right)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/And.Int64.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/And.Int64.cs new file mode 100644 index 0000000000..f6c22b36de --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/And.Int64.cs @@ -0,0 +1,315 @@ +// 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 AndInt64() + { + var test = new SimpleBinaryOpTest__AndInt64(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + // 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(); + + // 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(); + + // 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 works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + 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__AndInt64 + { + private const int VectorSize = 16; + private const int ElementCount = VectorSize / sizeof(Int64); + + private static Int64[] _data1 = new Int64[ElementCount]; + private static Int64[] _data2 = new Int64[ElementCount]; + + private static Vector128<Int64> _clsVar1; + private static Vector128<Int64> _clsVar2; + + private Vector128<Int64> _fld1; + private Vector128<Int64> _fld2; + + private SimpleBinaryOpTest__DataTable<Int64> _dataTable; + + static SimpleBinaryOpTest__AndInt64() + { + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (long)(random.Next(int.MinValue, int.MaxValue)); _data2[i] = (long)(random.Next(int.MinValue, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int64>, byte>(ref _clsVar1), ref Unsafe.As<Int64, byte>(ref _data2[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int64>, byte>(ref _clsVar2), ref Unsafe.As<Int64, byte>(ref _data1[0]), VectorSize); + } + + public SimpleBinaryOpTest__AndInt64() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (long)(random.Next(int.MinValue, int.MaxValue)); _data2[i] = (long)(random.Next(int.MinValue, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int64>, byte>(ref _fld1), ref Unsafe.As<Int64, byte>(ref _data1[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int64>, byte>(ref _fld2), ref Unsafe.As<Int64, byte>(ref _data2[0]), VectorSize); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (long)(random.Next(int.MinValue, int.MaxValue)); _data2[i] = (long)(random.Next(int.MinValue, int.MaxValue)); } + _dataTable = new SimpleBinaryOpTest__DataTable<Int64>(_data1, _data2, new Int64[ElementCount], VectorSize); + } + + public bool IsSupported => Sse2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse2.And( + Unsafe.Read<Vector128<Int64>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<Int64>>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse2.And( + Sse2.LoadVector128((Int64*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Int64*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse2.And( + Sse2.LoadAlignedVector128((Int64*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Int64*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.And), new Type[] { typeof(Vector128<Int64>), typeof(Vector128<Int64>) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector128<Int64>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<Int64>>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Int64>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.And), new Type[] { typeof(Vector128<Int64>), typeof(Vector128<Int64>) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Int64*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Int64*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Int64>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.And), new Type[] { typeof(Vector128<Int64>), typeof(Vector128<Int64>) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Int64*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Int64*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Int64>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse2.And( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read<Vector128<Int64>>(_dataTable.inArray1Ptr); + var right = Unsafe.Read<Vector128<Int64>>(_dataTable.inArray2Ptr); + var result = Sse2.And(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((Int64*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((Int64*)(_dataTable.inArray2Ptr)); + var result = Sse2.And(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((Int64*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((Int64*)(_dataTable.inArray2Ptr)); + var result = Sse2.And(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__AndInt64(); + var result = Sse2.And(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse2.And(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128<Int64> left, Vector128<Int64> right, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[ElementCount]; + Int64[] inArray2 = new Int64[ElementCount]; + Int64[] outArray = new Int64[ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int64, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[ElementCount]; + Int64[] inArray2 = new Int64[ElementCount]; + Int64[] outArray = new Int64[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int64, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int64, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int64, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int64[] left, Int64[] right, Int64[] result, [CallerMemberName] string method = "") + { + if ((long)(left[0] & right[0]) != result[0]) + { + Succeeded = false; + } + else + { + for (var i = 1; i < left.Length; i++) + { + if ((long)(left[i] & right[i]) != result[i]) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Sse2)}.{nameof(Sse2.And)}<Int64>: {method} failed:"); + Console.WriteLine($" left: ({string.Join(", ", left)})"); + Console.WriteLine($" right: ({string.Join(", ", right)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/And.SByte.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/And.SByte.cs new file mode 100644 index 0000000000..6bef767cfb --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/And.SByte.cs @@ -0,0 +1,315 @@ +// 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 AndSByte() + { + var test = new SimpleBinaryOpTest__AndSByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + // 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(); + + // 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(); + + // 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 works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + 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__AndSByte + { + private const int VectorSize = 16; + private const int ElementCount = VectorSize / sizeof(SByte); + + private static SByte[] _data1 = new SByte[ElementCount]; + private static SByte[] _data2 = new SByte[ElementCount]; + + private static Vector128<SByte> _clsVar1; + private static Vector128<SByte> _clsVar2; + + private Vector128<SByte> _fld1; + private Vector128<SByte> _fld2; + + private SimpleBinaryOpTest__DataTable<SByte> _dataTable; + + static SimpleBinaryOpTest__AndSByte() + { + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue)); _data2[i] = (sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<SByte>, byte>(ref _clsVar1), ref Unsafe.As<SByte, byte>(ref _data2[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<SByte>, byte>(ref _clsVar2), ref Unsafe.As<SByte, byte>(ref _data1[0]), VectorSize); + } + + public SimpleBinaryOpTest__AndSByte() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue)); _data2[i] = (sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<SByte>, byte>(ref _fld1), ref Unsafe.As<SByte, byte>(ref _data1[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<SByte>, byte>(ref _fld2), ref Unsafe.As<SByte, byte>(ref _data2[0]), VectorSize); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue)); _data2[i] = (sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue)); } + _dataTable = new SimpleBinaryOpTest__DataTable<SByte>(_data1, _data2, new SByte[ElementCount], VectorSize); + } + + public bool IsSupported => Sse2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse2.And( + Unsafe.Read<Vector128<SByte>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<SByte>>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse2.And( + Sse2.LoadVector128((SByte*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((SByte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse2.And( + Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.And), new Type[] { typeof(Vector128<SByte>), typeof(Vector128<SByte>) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector128<SByte>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<SByte>>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<SByte>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.And), new Type[] { typeof(Vector128<SByte>), typeof(Vector128<SByte>) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((SByte*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((SByte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<SByte>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.And), new Type[] { typeof(Vector128<SByte>), typeof(Vector128<SByte>) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<SByte>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse2.And( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read<Vector128<SByte>>(_dataTable.inArray1Ptr); + var right = Unsafe.Read<Vector128<SByte>>(_dataTable.inArray2Ptr); + var result = Sse2.And(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((SByte*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((SByte*)(_dataTable.inArray2Ptr)); + var result = Sse2.And(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArray2Ptr)); + var result = Sse2.And(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__AndSByte(); + var result = Sse2.And(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse2.And(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128<SByte> left, Vector128<SByte> right, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[ElementCount]; + SByte[] inArray2 = new SByte[ElementCount]; + SByte[] outArray = new SByte[ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<SByte, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[ElementCount]; + SByte[] inArray2 = new SByte[ElementCount]; + SByte[] outArray = new SByte[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<SByte, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<SByte, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<SByte, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(SByte[] left, SByte[] right, SByte[] result, [CallerMemberName] string method = "") + { + if ((sbyte)(left[0] & right[0]) != result[0]) + { + Succeeded = false; + } + else + { + for (var i = 1; i < left.Length; i++) + { + if ((sbyte)(left[i] & right[i]) != result[i]) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Sse2)}.{nameof(Sse2.And)}<SByte>: {method} failed:"); + Console.WriteLine($" left: ({string.Join(", ", left)})"); + Console.WriteLine($" right: ({string.Join(", ", right)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/And.UInt16.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/And.UInt16.cs new file mode 100644 index 0000000000..550dd341f7 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/And.UInt16.cs @@ -0,0 +1,315 @@ +// 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 AndUInt16() + { + var test = new SimpleBinaryOpTest__AndUInt16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + // 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(); + + // 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(); + + // 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 works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + 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__AndUInt16 + { + private const int VectorSize = 16; + private const int ElementCount = VectorSize / sizeof(UInt16); + + private static UInt16[] _data1 = new UInt16[ElementCount]; + private static UInt16[] _data2 = new UInt16[ElementCount]; + + private static Vector128<UInt16> _clsVar1; + private static Vector128<UInt16> _clsVar2; + + private Vector128<UInt16> _fld1; + private Vector128<UInt16> _fld2; + + private SimpleBinaryOpTest__DataTable<UInt16> _dataTable; + + static SimpleBinaryOpTest__AndUInt16() + { + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (ushort)(random.Next(0, ushort.MaxValue)); _data2[i] = (ushort)(random.Next(0, ushort.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt16>, byte>(ref _clsVar1), ref Unsafe.As<UInt16, byte>(ref _data2[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt16>, byte>(ref _clsVar2), ref Unsafe.As<UInt16, byte>(ref _data1[0]), VectorSize); + } + + public SimpleBinaryOpTest__AndUInt16() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (ushort)(random.Next(0, ushort.MaxValue)); _data2[i] = (ushort)(random.Next(0, ushort.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt16>, byte>(ref _fld1), ref Unsafe.As<UInt16, byte>(ref _data1[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt16>, byte>(ref _fld2), ref Unsafe.As<UInt16, byte>(ref _data2[0]), VectorSize); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (ushort)(random.Next(0, ushort.MaxValue)); _data2[i] = (ushort)(random.Next(0, ushort.MaxValue)); } + _dataTable = new SimpleBinaryOpTest__DataTable<UInt16>(_data1, _data2, new UInt16[ElementCount], VectorSize); + } + + public bool IsSupported => Sse2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse2.And( + Unsafe.Read<Vector128<UInt16>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<UInt16>>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse2.And( + Sse2.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse2.And( + Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.And), new Type[] { typeof(Vector128<UInt16>), typeof(Vector128<UInt16>) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector128<UInt16>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<UInt16>>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<UInt16>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.And), new Type[] { typeof(Vector128<UInt16>), typeof(Vector128<UInt16>) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<UInt16>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.And), new Type[] { typeof(Vector128<UInt16>), typeof(Vector128<UInt16>) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<UInt16>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse2.And( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read<Vector128<UInt16>>(_dataTable.inArray1Ptr); + var right = Unsafe.Read<Vector128<UInt16>>(_dataTable.inArray2Ptr); + var result = Sse2.And(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)); + var result = Sse2.And(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArray2Ptr)); + var result = Sse2.And(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__AndUInt16(); + var result = Sse2.And(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse2.And(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128<UInt16> left, Vector128<UInt16> right, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[ElementCount]; + UInt16[] inArray2 = new UInt16[ElementCount]; + UInt16[] outArray = new UInt16[ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt16, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[ElementCount]; + UInt16[] inArray2 = new UInt16[ElementCount]; + UInt16[] outArray = new UInt16[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt16, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt16, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt16, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt16[] left, UInt16[] right, UInt16[] result, [CallerMemberName] string method = "") + { + if ((ushort)(left[0] & right[0]) != result[0]) + { + Succeeded = false; + } + else + { + for (var i = 1; i < left.Length; i++) + { + if ((ushort)(left[i] & right[i]) != result[i]) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Sse2)}.{nameof(Sse2.And)}<UInt16>: {method} failed:"); + Console.WriteLine($" left: ({string.Join(", ", left)})"); + Console.WriteLine($" right: ({string.Join(", ", right)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/And.UInt32.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/And.UInt32.cs new file mode 100644 index 0000000000..aa2329e740 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/And.UInt32.cs @@ -0,0 +1,315 @@ +// 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 AndUInt32() + { + var test = new SimpleBinaryOpTest__AndUInt32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + // 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(); + + // 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(); + + // 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 works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + 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__AndUInt32 + { + private const int VectorSize = 16; + private const int ElementCount = VectorSize / sizeof(UInt32); + + private static UInt32[] _data1 = new UInt32[ElementCount]; + private static UInt32[] _data2 = new UInt32[ElementCount]; + + private static Vector128<UInt32> _clsVar1; + private static Vector128<UInt32> _clsVar2; + + private Vector128<UInt32> _fld1; + private Vector128<UInt32> _fld2; + + private SimpleBinaryOpTest__DataTable<UInt32> _dataTable; + + static SimpleBinaryOpTest__AndUInt32() + { + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (uint)(random.Next(0, int.MaxValue)); _data2[i] = (uint)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt32>, byte>(ref _clsVar1), ref Unsafe.As<UInt32, byte>(ref _data2[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt32>, byte>(ref _clsVar2), ref Unsafe.As<UInt32, byte>(ref _data1[0]), VectorSize); + } + + public SimpleBinaryOpTest__AndUInt32() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (uint)(random.Next(0, int.MaxValue)); _data2[i] = (uint)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt32>, byte>(ref _fld1), ref Unsafe.As<UInt32, byte>(ref _data1[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt32>, byte>(ref _fld2), ref Unsafe.As<UInt32, byte>(ref _data2[0]), VectorSize); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (uint)(random.Next(0, int.MaxValue)); _data2[i] = (uint)(random.Next(0, int.MaxValue)); } + _dataTable = new SimpleBinaryOpTest__DataTable<UInt32>(_data1, _data2, new UInt32[ElementCount], VectorSize); + } + + public bool IsSupported => Sse2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse2.And( + Unsafe.Read<Vector128<UInt32>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<UInt32>>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse2.And( + Sse2.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse2.And( + Sse2.LoadAlignedVector128((UInt32*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((UInt32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.And), new Type[] { typeof(Vector128<UInt32>), typeof(Vector128<UInt32>) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector128<UInt32>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<UInt32>>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<UInt32>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.And), new Type[] { typeof(Vector128<UInt32>), typeof(Vector128<UInt32>) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<UInt32>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.And), new Type[] { typeof(Vector128<UInt32>), typeof(Vector128<UInt32>) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((UInt32*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((UInt32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<UInt32>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse2.And( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read<Vector128<UInt32>>(_dataTable.inArray1Ptr); + var right = Unsafe.Read<Vector128<UInt32>>(_dataTable.inArray2Ptr); + var result = Sse2.And(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)); + var result = Sse2.And(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((UInt32*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((UInt32*)(_dataTable.inArray2Ptr)); + var result = Sse2.And(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__AndUInt32(); + var result = Sse2.And(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse2.And(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128<UInt32> left, Vector128<UInt32> right, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[ElementCount]; + UInt32[] inArray2 = new UInt32[ElementCount]; + UInt32[] outArray = new UInt32[ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt32, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[ElementCount]; + UInt32[] inArray2 = new UInt32[ElementCount]; + UInt32[] outArray = new UInt32[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt32, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt32, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt32, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt32[] left, UInt32[] right, UInt32[] result, [CallerMemberName] string method = "") + { + if ((uint)(left[0] & right[0]) != result[0]) + { + Succeeded = false; + } + else + { + for (var i = 1; i < left.Length; i++) + { + if ((uint)(left[i] & right[i]) != result[i]) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Sse2)}.{nameof(Sse2.And)}<UInt32>: {method} failed:"); + Console.WriteLine($" left: ({string.Join(", ", left)})"); + Console.WriteLine($" right: ({string.Join(", ", right)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/And.UInt64.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/And.UInt64.cs new file mode 100644 index 0000000000..dbfbbf68fc --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/And.UInt64.cs @@ -0,0 +1,315 @@ +// 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 AndUInt64() + { + var test = new SimpleBinaryOpTest__AndUInt64(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + // 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(); + + // 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(); + + // 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 works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + 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__AndUInt64 + { + private const int VectorSize = 16; + private const int ElementCount = VectorSize / sizeof(UInt64); + + private static UInt64[] _data1 = new UInt64[ElementCount]; + private static UInt64[] _data2 = new UInt64[ElementCount]; + + private static Vector128<UInt64> _clsVar1; + private static Vector128<UInt64> _clsVar2; + + private Vector128<UInt64> _fld1; + private Vector128<UInt64> _fld2; + + private SimpleBinaryOpTest__DataTable<UInt64> _dataTable; + + static SimpleBinaryOpTest__AndUInt64() + { + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (ulong)(random.Next(0, int.MaxValue)); _data2[i] = (ulong)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt64>, byte>(ref _clsVar1), ref Unsafe.As<UInt64, byte>(ref _data2[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt64>, byte>(ref _clsVar2), ref Unsafe.As<UInt64, byte>(ref _data1[0]), VectorSize); + } + + public SimpleBinaryOpTest__AndUInt64() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (ulong)(random.Next(0, int.MaxValue)); _data2[i] = (ulong)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt64>, byte>(ref _fld1), ref Unsafe.As<UInt64, byte>(ref _data1[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt64>, byte>(ref _fld2), ref Unsafe.As<UInt64, byte>(ref _data2[0]), VectorSize); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (ulong)(random.Next(0, int.MaxValue)); _data2[i] = (ulong)(random.Next(0, int.MaxValue)); } + _dataTable = new SimpleBinaryOpTest__DataTable<UInt64>(_data1, _data2, new UInt64[ElementCount], VectorSize); + } + + public bool IsSupported => Sse2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse2.And( + Unsafe.Read<Vector128<UInt64>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<UInt64>>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse2.And( + Sse2.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((UInt64*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse2.And( + Sse2.LoadAlignedVector128((UInt64*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((UInt64*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.And), new Type[] { typeof(Vector128<UInt64>), typeof(Vector128<UInt64>) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector128<UInt64>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<UInt64>>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<UInt64>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.And), new Type[] { typeof(Vector128<UInt64>), typeof(Vector128<UInt64>) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((UInt64*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<UInt64>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.And), new Type[] { typeof(Vector128<UInt64>), typeof(Vector128<UInt64>) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((UInt64*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((UInt64*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<UInt64>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse2.And( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read<Vector128<UInt64>>(_dataTable.inArray1Ptr); + var right = Unsafe.Read<Vector128<UInt64>>(_dataTable.inArray2Ptr); + var result = Sse2.And(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((UInt64*)(_dataTable.inArray2Ptr)); + var result = Sse2.And(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((UInt64*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((UInt64*)(_dataTable.inArray2Ptr)); + var result = Sse2.And(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__AndUInt64(); + var result = Sse2.And(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse2.And(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128<UInt64> left, Vector128<UInt64> right, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray1 = new UInt64[ElementCount]; + UInt64[] inArray2 = new UInt64[ElementCount]; + UInt64[] outArray = new UInt64[ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt64, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray1 = new UInt64[ElementCount]; + UInt64[] inArray2 = new UInt64[ElementCount]; + UInt64[] outArray = new UInt64[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt64, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt64, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt64, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt64[] left, UInt64[] right, UInt64[] result, [CallerMemberName] string method = "") + { + if ((ulong)(left[0] & right[0]) != result[0]) + { + Succeeded = false; + } + else + { + for (var i = 1; i < left.Length; i++) + { + if ((ulong)(left[i] & right[i]) != result[i]) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Sse2)}.{nameof(Sse2.And)}<UInt64>: {method} failed:"); + Console.WriteLine($" left: ({string.Join(", ", left)})"); + Console.WriteLine($" right: ({string.Join(", ", right)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/And.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/And.cs deleted file mode 100644 index 2a54745135..0000000000 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/And.cs +++ /dev/null @@ -1,187 +0,0 @@ -// 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. -// - -using System; -using System.Runtime.Intrinsics; -using System.Runtime.Intrinsics.X86; - -namespace IntelHardwareIntrinsicTest -{ - internal static partial class Program - { - const int Pass = 100; - const int Fail = 0; - - static unsafe int Main(string[] args) - { - int testResult = Pass; - int testsCount = 21; - string methodUnderTestName = nameof(Sse2.And); - - if (Sse2.IsSupported) - { - using (var doubleTable = TestTableSse2<double>.Create(testsCount)) - using (var longTable = TestTableSse2<long>.Create(testsCount)) - using (var ulongTable = TestTableSse2<ulong>.Create(testsCount)) - using (var intTable = TestTableSse2<int>.Create(testsCount)) - using (var uintTable = TestTableSse2<uint>.Create(testsCount)) - using (var shortTable = TestTableSse2<short>.Create(testsCount)) - using (var ushortTable = TestTableSse2<ushort>.Create(testsCount)) - using (var sbyteTable = TestTableSse2<sbyte>.Create(testsCount)) - using (var byteTable = TestTableSse2<byte>.Create(testsCount)) - { - for (int i = 0; i < testsCount; i++) - { - (Vector128<double>, Vector128<double>, Vector128<double>) value = doubleTable[i]; - var result = Sse2.And(value.Item1, value.Item2); - doubleTable.SetOutArray(result); - } - - for (int i = 0; i < testsCount; i++) - { - (Vector128<long>, Vector128<long>, Vector128<long>) value = longTable[i]; - var result = Sse2.And(value.Item1, value.Item2); - longTable.SetOutArray(result); - } - - for (int i = 0; i < testsCount; i++) - { - (Vector128<ulong>, Vector128<ulong>, Vector128<ulong>) value = ulongTable[i]; - var result = Sse2.And(value.Item1, value.Item2); - ulongTable.SetOutArray(result); - } - - for (int i = 0; i < testsCount; i++) - { - (Vector128<int>, Vector128<int>, Vector128<int>) value = intTable[i]; - var result = Sse2.And(value.Item1, value.Item2); - intTable.SetOutArray(result); - } - - for (int i = 0; i < testsCount; i++) - { - (Vector128<uint>, Vector128<uint>, Vector128<uint>) value = uintTable[i]; - var result = Sse2.And(value.Item1, value.Item2); - uintTable.SetOutArray(result); - } - - for (int i = 0; i < testsCount; i++) - { - (Vector128<short>, Vector128<short>, Vector128<short>) value = shortTable[i]; - var result = Sse2.And(value.Item1, value.Item2); - shortTable.SetOutArray(result); - } - - for (int i = 0; i < testsCount; i++) - { - (Vector128<ushort>, Vector128<ushort>, Vector128<ushort>) value = ushortTable[i]; - var result = Sse2.And(value.Item1, value.Item2); - ushortTable.SetOutArray(result); - } - - for (int i = 0; i < testsCount; i++) - { - (Vector128<sbyte>, Vector128<sbyte>, Vector128<sbyte>) value = sbyteTable[i]; - var result = Sse2.And(value.Item1, value.Item2); - sbyteTable.SetOutArray(result); - } - - for (int i = 0; i < testsCount; i++) - { - (Vector128<byte>, Vector128<byte>, Vector128<byte>) value = byteTable[i]; - var result = Sse2.And(value.Item1, value.Item2); - byteTable.SetOutArray(result); - } - - CheckMethod<double> checkDouble = (double x, double y, double z, ref double a) => (a = BinaryAnd(x, y)) == z; - - if (!doubleTable.CheckResult(checkDouble)) - { - PrintError(doubleTable, methodUnderTestName, "(double x, double y, double z, ref double a) => (a = BinaryAnd(x, y)) == z", checkDouble); - testResult = Fail; - } - - CheckMethod<long> checkLong = (long x, long y, long z, ref long a) => (a = x & y) == z; - - if (!longTable.CheckResult(checkLong)) - { - PrintError(longTable, methodUnderTestName, "(long x, long y, long z, ref long a) => (a = x & y) == z", checkLong); - testResult = Fail; - } - - CheckMethod<ulong> checkUlong = (ulong x, ulong y, ulong z, ref ulong a) => (a = x & y) == z; - - if (!longTable.CheckResult(checkLong)) - { - PrintError(ulongTable, methodUnderTestName, "(ulong x, ulong y, ulong z, ref ulong a) => (a = x & y) == z", checkUlong); - testResult = Fail; - } - - CheckMethod<int> checkInt32 = (int x, int y, int z, ref int a) => (a = x & y) == z; - - if (!intTable.CheckResult(checkInt32)) - { - PrintError(intTable, methodUnderTestName, "(int x, int y, int z, ref int a) => (a = x & y) == z", checkInt32); - testResult = Fail; - } - - CheckMethod<uint> checkUInt32 = (uint x, uint y, uint z, ref uint a) => (a = x & y) == z; - - if (!uintTable.CheckResult(checkUInt32)) - { - PrintError(uintTable, methodUnderTestName, "(uint x, uint y, uint z, ref uint a) => (a = x & y) == z", checkUInt32); - testResult = Fail; - } - - CheckMethod<short> checkInt16 = (short x, short y, short z, ref short a) => (a = (short)(x & y)) == z; - - if (!shortTable.CheckResult(checkInt16)) - { - PrintError(shortTable, methodUnderTestName, "(short x, short y, short z, ref short a) => (a = (short)(x & y)) == z", checkInt16); - testResult = Fail; - } - - CheckMethod<ushort> checkUInt16 = (ushort x, ushort y, ushort z, ref ushort a) => (a = (ushort)(x & y)) == z; - - if (!ushortTable.CheckResult(checkUInt16)) - { - PrintError(ushortTable, methodUnderTestName, "(ushort x, ushort y, ushort z, ref ushort a) => (a = (ushort)(x & y)) == z", checkUInt16); - testResult = Fail; - } - - CheckMethod<sbyte> checkSByte = (sbyte x, sbyte y, sbyte z, ref sbyte a) => (a = (sbyte)(x & y)) == z; - - if (!sbyteTable.CheckResult(checkSByte)) - { - PrintError(sbyteTable, methodUnderTestName, "(sbyte x, sbyte y, sbyte z, ref sbyte a) => (a = (sbyte)(x & y)) == z", checkSByte); - testResult = Fail; - } - - CheckMethod<byte> checkByte = (byte x, byte y, byte z, ref byte a) => (a = (byte)(x & y)) == z; - - if (!byteTable.CheckResult(checkByte)) - { - PrintError(byteTable, methodUnderTestName, "(byte x, byte y, byte z, ref byte a) => (a = (byte)(x & y)) == z", checkByte); - testResult = Fail; - } - } - } - else - { - Console.WriteLine($"Sse2.IsSupported: {Sse2.IsSupported}, skipped tests of {typeof(Sse2)}.{methodUnderTestName}"); - } - - return testResult; - } - - public static unsafe double BinaryAnd(double x, double y) - { - var xUlong = BitConverter.ToUInt64(BitConverter.GetBytes(x)); - var yUlong = BitConverter.ToUInt64(BitConverter.GetBytes(y)); - var longAnd = xUlong & yUlong; - return BitConverter.ToDouble(BitConverter.GetBytes(longAnd)); - } - } -} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/AndNot.Byte.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/AndNot.Byte.cs new file mode 100644 index 0000000000..ae9c583b95 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/AndNot.Byte.cs @@ -0,0 +1,315 @@ +// 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 AndNotByte() + { + var test = new SimpleBinaryOpTest__AndNotByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + // 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(); + + // 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(); + + // 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 works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + 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__AndNotByte + { + private const int VectorSize = 16; + private const int ElementCount = VectorSize / sizeof(Byte); + + private static Byte[] _data1 = new Byte[ElementCount]; + private static Byte[] _data2 = new Byte[ElementCount]; + + private static Vector128<Byte> _clsVar1; + private static Vector128<Byte> _clsVar2; + + private Vector128<Byte> _fld1; + private Vector128<Byte> _fld2; + + private SimpleBinaryOpTest__DataTable<Byte> _dataTable; + + static SimpleBinaryOpTest__AndNotByte() + { + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (byte)(random.Next(0, byte.MaxValue)); _data2[i] = (byte)(random.Next(0, byte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Byte>, byte>(ref _clsVar1), ref Unsafe.As<Byte, byte>(ref _data2[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Byte>, byte>(ref _clsVar2), ref Unsafe.As<Byte, byte>(ref _data1[0]), VectorSize); + } + + public SimpleBinaryOpTest__AndNotByte() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (byte)(random.Next(0, byte.MaxValue)); _data2[i] = (byte)(random.Next(0, byte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Byte>, byte>(ref _fld1), ref Unsafe.As<Byte, byte>(ref _data1[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Byte>, byte>(ref _fld2), ref Unsafe.As<Byte, byte>(ref _data2[0]), VectorSize); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (byte)(random.Next(0, byte.MaxValue)); _data2[i] = (byte)(random.Next(0, byte.MaxValue)); } + _dataTable = new SimpleBinaryOpTest__DataTable<Byte>(_data1, _data2, new Byte[ElementCount], VectorSize); + } + + public bool IsSupported => Sse2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse2.AndNot( + Unsafe.Read<Vector128<Byte>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<Byte>>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse2.AndNot( + Sse2.LoadVector128((Byte*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Byte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse2.AndNot( + Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.AndNot), new Type[] { typeof(Vector128<Byte>), typeof(Vector128<Byte>) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector128<Byte>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<Byte>>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Byte>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.AndNot), new Type[] { typeof(Vector128<Byte>), typeof(Vector128<Byte>) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Byte*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Byte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Byte>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.AndNot), new Type[] { typeof(Vector128<Byte>), typeof(Vector128<Byte>) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Byte>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse2.AndNot( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read<Vector128<Byte>>(_dataTable.inArray1Ptr); + var right = Unsafe.Read<Vector128<Byte>>(_dataTable.inArray2Ptr); + var result = Sse2.AndNot(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((Byte*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((Byte*)(_dataTable.inArray2Ptr)); + var result = Sse2.AndNot(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray2Ptr)); + var result = Sse2.AndNot(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__AndNotByte(); + var result = Sse2.AndNot(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse2.AndNot(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128<Byte> left, Vector128<Byte> right, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[ElementCount]; + Byte[] inArray2 = new Byte[ElementCount]; + Byte[] outArray = new Byte[ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Byte, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[ElementCount]; + Byte[] inArray2 = new Byte[ElementCount]; + Byte[] outArray = new Byte[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Byte, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Byte, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Byte, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Byte[] left, Byte[] right, Byte[] result, [CallerMemberName] string method = "") + { + if ((byte)(~left[0] & right[0]) != result[0]) + { + Succeeded = false; + } + else + { + for (var i = 1; i < left.Length; i++) + { + if ((byte)(~left[i] & right[i]) != result[i]) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Sse2)}.{nameof(Sse2.AndNot)}<Byte>: {method} failed:"); + Console.WriteLine($" left: ({string.Join(", ", left)})"); + Console.WriteLine($" right: ({string.Join(", ", right)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/AndNot.Double.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/AndNot.Double.cs new file mode 100644 index 0000000000..9a072eebce --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/AndNot.Double.cs @@ -0,0 +1,315 @@ +// 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 AndNotDouble() + { + var test = new SimpleBinaryOpTest__AndNotDouble(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + // 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(); + + // 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(); + + // 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 works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + 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__AndNotDouble + { + private const int VectorSize = 16; + private const int ElementCount = VectorSize / sizeof(Double); + + private static Double[] _data1 = new Double[ElementCount]; + private static Double[] _data2 = new Double[ElementCount]; + + private static Vector128<Double> _clsVar1; + private static Vector128<Double> _clsVar2; + + private Vector128<Double> _fld1; + private Vector128<Double> _fld2; + + private SimpleBinaryOpTest__DataTable<Double> _dataTable; + + static SimpleBinaryOpTest__AndNotDouble() + { + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (double)(random.NextDouble()); _data2[i] = (double)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Double>, byte>(ref _clsVar1), ref Unsafe.As<Double, byte>(ref _data2[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Double>, byte>(ref _clsVar2), ref Unsafe.As<Double, byte>(ref _data1[0]), VectorSize); + } + + public SimpleBinaryOpTest__AndNotDouble() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (double)(random.NextDouble()); _data2[i] = (double)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Double>, byte>(ref _fld1), ref Unsafe.As<Double, byte>(ref _data1[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Double>, byte>(ref _fld2), ref Unsafe.As<Double, byte>(ref _data2[0]), VectorSize); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (double)(random.NextDouble()); _data2[i] = (double)(random.NextDouble()); } + _dataTable = new SimpleBinaryOpTest__DataTable<Double>(_data1, _data2, new Double[ElementCount], VectorSize); + } + + public bool IsSupported => Sse2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse2.AndNot( + Unsafe.Read<Vector128<Double>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<Double>>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse2.AndNot( + Sse2.LoadVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Double*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse2.AndNot( + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.AndNot), new Type[] { typeof(Vector128<Double>), typeof(Vector128<Double>) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector128<Double>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<Double>>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Double>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.AndNot), new Type[] { typeof(Vector128<Double>), typeof(Vector128<Double>) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Double*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Double>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.AndNot), new Type[] { typeof(Vector128<Double>), typeof(Vector128<Double>) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Double>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse2.AndNot( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read<Vector128<Double>>(_dataTable.inArray1Ptr); + var right = Unsafe.Read<Vector128<Double>>(_dataTable.inArray2Ptr); + var result = Sse2.AndNot(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((Double*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((Double*)(_dataTable.inArray2Ptr)); + var result = Sse2.AndNot(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray2Ptr)); + var result = Sse2.AndNot(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__AndNotDouble(); + var result = Sse2.AndNot(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse2.AndNot(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128<Double> left, Vector128<Double> right, void* result, [CallerMemberName] string method = "") + { + Double[] inArray1 = new Double[ElementCount]; + Double[] inArray2 = new Double[ElementCount]; + Double[] outArray = new Double[ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Double[] inArray1 = new Double[ElementCount]; + Double[] inArray2 = new Double[ElementCount]; + Double[] outArray = new Double[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Double[] left, Double[] right, Double[] result, [CallerMemberName] string method = "") + { + if ((~BitConverter.DoubleToInt64Bits(left[0]) & BitConverter.DoubleToInt64Bits(right[0])) != BitConverter.DoubleToInt64Bits(result[0])) + { + Succeeded = false; + } + else + { + for (var i = 1; i < left.Length; i++) + { + if ((~BitConverter.DoubleToInt64Bits(left[i]) & BitConverter.DoubleToInt64Bits(right[i])) != BitConverter.DoubleToInt64Bits(result[i])) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Sse2)}.{nameof(Sse2.AndNot)}<Double>: {method} failed:"); + Console.WriteLine($" left: ({string.Join(", ", left)})"); + Console.WriteLine($" right: ({string.Join(", ", right)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/AndNot.Int16.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/AndNot.Int16.cs new file mode 100644 index 0000000000..695826926f --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/AndNot.Int16.cs @@ -0,0 +1,315 @@ +// 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 AndNotInt16() + { + var test = new SimpleBinaryOpTest__AndNotInt16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + // 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(); + + // 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(); + + // 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 works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + 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__AndNotInt16 + { + private const int VectorSize = 16; + private const int ElementCount = VectorSize / sizeof(Int16); + + private static Int16[] _data1 = new Int16[ElementCount]; + private static Int16[] _data2 = new Int16[ElementCount]; + + private static Vector128<Int16> _clsVar1; + private static Vector128<Int16> _clsVar2; + + private Vector128<Int16> _fld1; + private Vector128<Int16> _fld2; + + private SimpleBinaryOpTest__DataTable<Int16> _dataTable; + + static SimpleBinaryOpTest__AndNotInt16() + { + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (short)(random.Next(short.MinValue, short.MaxValue)); _data2[i] = (short)(random.Next(short.MinValue, short.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int16>, byte>(ref _clsVar1), ref Unsafe.As<Int16, byte>(ref _data2[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int16>, byte>(ref _clsVar2), ref Unsafe.As<Int16, byte>(ref _data1[0]), VectorSize); + } + + public SimpleBinaryOpTest__AndNotInt16() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (short)(random.Next(short.MinValue, short.MaxValue)); _data2[i] = (short)(random.Next(short.MinValue, short.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int16>, byte>(ref _fld1), ref Unsafe.As<Int16, byte>(ref _data1[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int16>, byte>(ref _fld2), ref Unsafe.As<Int16, byte>(ref _data2[0]), VectorSize); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (short)(random.Next(short.MinValue, short.MaxValue)); _data2[i] = (short)(random.Next(short.MinValue, short.MaxValue)); } + _dataTable = new SimpleBinaryOpTest__DataTable<Int16>(_data1, _data2, new Int16[ElementCount], VectorSize); + } + + public bool IsSupported => Sse2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse2.AndNot( + Unsafe.Read<Vector128<Int16>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<Int16>>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse2.AndNot( + Sse2.LoadVector128((Int16*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Int16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse2.AndNot( + Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.AndNot), new Type[] { typeof(Vector128<Int16>), typeof(Vector128<Int16>) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector128<Int16>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<Int16>>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Int16>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.AndNot), new Type[] { typeof(Vector128<Int16>), typeof(Vector128<Int16>) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Int16*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Int16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Int16>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.AndNot), new Type[] { typeof(Vector128<Int16>), typeof(Vector128<Int16>) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Int16>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse2.AndNot( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read<Vector128<Int16>>(_dataTable.inArray1Ptr); + var right = Unsafe.Read<Vector128<Int16>>(_dataTable.inArray2Ptr); + var result = Sse2.AndNot(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((Int16*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((Int16*)(_dataTable.inArray2Ptr)); + var result = Sse2.AndNot(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray2Ptr)); + var result = Sse2.AndNot(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__AndNotInt16(); + var result = Sse2.AndNot(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse2.AndNot(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128<Int16> left, Vector128<Int16> right, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[ElementCount]; + Int16[] inArray2 = new Int16[ElementCount]; + Int16[] outArray = new Int16[ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int16, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[ElementCount]; + Int16[] inArray2 = new Int16[ElementCount]; + Int16[] outArray = new Int16[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int16, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int16, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int16, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int16[] left, Int16[] right, Int16[] result, [CallerMemberName] string method = "") + { + if ((short)(~left[0] & right[0]) != result[0]) + { + Succeeded = false; + } + else + { + for (var i = 1; i < left.Length; i++) + { + if ((short)(~left[i] & right[i]) != result[i]) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Sse2)}.{nameof(Sse2.AndNot)}<Int16>: {method} failed:"); + Console.WriteLine($" left: ({string.Join(", ", left)})"); + Console.WriteLine($" right: ({string.Join(", ", right)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/AndNot.Int32.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/AndNot.Int32.cs new file mode 100644 index 0000000000..e381266bee --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/AndNot.Int32.cs @@ -0,0 +1,315 @@ +// 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 AndNotInt32() + { + var test = new SimpleBinaryOpTest__AndNotInt32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + // 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(); + + // 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(); + + // 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 works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + 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__AndNotInt32 + { + private const int VectorSize = 16; + private const int ElementCount = VectorSize / sizeof(Int32); + + private static Int32[] _data1 = new Int32[ElementCount]; + private static Int32[] _data2 = new Int32[ElementCount]; + + private static Vector128<Int32> _clsVar1; + private static Vector128<Int32> _clsVar2; + + private Vector128<Int32> _fld1; + private Vector128<Int32> _fld2; + + private SimpleBinaryOpTest__DataTable<Int32> _dataTable; + + static SimpleBinaryOpTest__AndNotInt32() + { + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (int)(random.Next(int.MinValue, int.MaxValue)); _data2[i] = (int)(random.Next(int.MinValue, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int32>, byte>(ref _clsVar1), ref Unsafe.As<Int32, byte>(ref _data2[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int32>, byte>(ref _clsVar2), ref Unsafe.As<Int32, byte>(ref _data1[0]), VectorSize); + } + + public SimpleBinaryOpTest__AndNotInt32() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (int)(random.Next(int.MinValue, int.MaxValue)); _data2[i] = (int)(random.Next(int.MinValue, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int32>, byte>(ref _fld1), ref Unsafe.As<Int32, byte>(ref _data1[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int32>, byte>(ref _fld2), ref Unsafe.As<Int32, byte>(ref _data2[0]), VectorSize); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (int)(random.Next(int.MinValue, int.MaxValue)); _data2[i] = (int)(random.Next(int.MinValue, int.MaxValue)); } + _dataTable = new SimpleBinaryOpTest__DataTable<Int32>(_data1, _data2, new Int32[ElementCount], VectorSize); + } + + public bool IsSupported => Sse2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse2.AndNot( + Unsafe.Read<Vector128<Int32>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<Int32>>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse2.AndNot( + Sse2.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Int32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse2.AndNot( + Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.AndNot), new Type[] { typeof(Vector128<Int32>), typeof(Vector128<Int32>) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector128<Int32>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<Int32>>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Int32>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.AndNot), new Type[] { typeof(Vector128<Int32>), typeof(Vector128<Int32>) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Int32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Int32>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.AndNot), new Type[] { typeof(Vector128<Int32>), typeof(Vector128<Int32>) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Int32>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse2.AndNot( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read<Vector128<Int32>>(_dataTable.inArray1Ptr); + var right = Unsafe.Read<Vector128<Int32>>(_dataTable.inArray2Ptr); + var result = Sse2.AndNot(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((Int32*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((Int32*)(_dataTable.inArray2Ptr)); + var result = Sse2.AndNot(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray2Ptr)); + var result = Sse2.AndNot(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__AndNotInt32(); + var result = Sse2.AndNot(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse2.AndNot(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128<Int32> left, Vector128<Int32> right, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[ElementCount]; + Int32[] inArray2 = new Int32[ElementCount]; + Int32[] outArray = new Int32[ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int32, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[ElementCount]; + Int32[] inArray2 = new Int32[ElementCount]; + Int32[] outArray = new Int32[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int32, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int32, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int32, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int32[] left, Int32[] right, Int32[] result, [CallerMemberName] string method = "") + { + if ((int)(~left[0] & right[0]) != result[0]) + { + Succeeded = false; + } + else + { + for (var i = 1; i < left.Length; i++) + { + if ((int)(~left[i] & right[i]) != result[i]) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Sse2)}.{nameof(Sse2.AndNot)}<Int32>: {method} failed:"); + Console.WriteLine($" left: ({string.Join(", ", left)})"); + Console.WriteLine($" right: ({string.Join(", ", right)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/AndNot.Int64.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/AndNot.Int64.cs new file mode 100644 index 0000000000..652825cb3a --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/AndNot.Int64.cs @@ -0,0 +1,315 @@ +// 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 AndNotInt64() + { + var test = new SimpleBinaryOpTest__AndNotInt64(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + // 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(); + + // 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(); + + // 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 works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + 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__AndNotInt64 + { + private const int VectorSize = 16; + private const int ElementCount = VectorSize / sizeof(Int64); + + private static Int64[] _data1 = new Int64[ElementCount]; + private static Int64[] _data2 = new Int64[ElementCount]; + + private static Vector128<Int64> _clsVar1; + private static Vector128<Int64> _clsVar2; + + private Vector128<Int64> _fld1; + private Vector128<Int64> _fld2; + + private SimpleBinaryOpTest__DataTable<Int64> _dataTable; + + static SimpleBinaryOpTest__AndNotInt64() + { + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (long)(random.Next(int.MinValue, int.MaxValue)); _data2[i] = (long)(random.Next(int.MinValue, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int64>, byte>(ref _clsVar1), ref Unsafe.As<Int64, byte>(ref _data2[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int64>, byte>(ref _clsVar2), ref Unsafe.As<Int64, byte>(ref _data1[0]), VectorSize); + } + + public SimpleBinaryOpTest__AndNotInt64() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (long)(random.Next(int.MinValue, int.MaxValue)); _data2[i] = (long)(random.Next(int.MinValue, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int64>, byte>(ref _fld1), ref Unsafe.As<Int64, byte>(ref _data1[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int64>, byte>(ref _fld2), ref Unsafe.As<Int64, byte>(ref _data2[0]), VectorSize); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (long)(random.Next(int.MinValue, int.MaxValue)); _data2[i] = (long)(random.Next(int.MinValue, int.MaxValue)); } + _dataTable = new SimpleBinaryOpTest__DataTable<Int64>(_data1, _data2, new Int64[ElementCount], VectorSize); + } + + public bool IsSupported => Sse2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse2.AndNot( + Unsafe.Read<Vector128<Int64>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<Int64>>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse2.AndNot( + Sse2.LoadVector128((Int64*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Int64*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse2.AndNot( + Sse2.LoadAlignedVector128((Int64*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Int64*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.AndNot), new Type[] { typeof(Vector128<Int64>), typeof(Vector128<Int64>) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector128<Int64>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<Int64>>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Int64>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.AndNot), new Type[] { typeof(Vector128<Int64>), typeof(Vector128<Int64>) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Int64*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Int64*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Int64>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.AndNot), new Type[] { typeof(Vector128<Int64>), typeof(Vector128<Int64>) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Int64*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Int64*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Int64>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse2.AndNot( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read<Vector128<Int64>>(_dataTable.inArray1Ptr); + var right = Unsafe.Read<Vector128<Int64>>(_dataTable.inArray2Ptr); + var result = Sse2.AndNot(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((Int64*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((Int64*)(_dataTable.inArray2Ptr)); + var result = Sse2.AndNot(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((Int64*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((Int64*)(_dataTable.inArray2Ptr)); + var result = Sse2.AndNot(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__AndNotInt64(); + var result = Sse2.AndNot(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse2.AndNot(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128<Int64> left, Vector128<Int64> right, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[ElementCount]; + Int64[] inArray2 = new Int64[ElementCount]; + Int64[] outArray = new Int64[ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int64, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[ElementCount]; + Int64[] inArray2 = new Int64[ElementCount]; + Int64[] outArray = new Int64[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int64, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int64, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int64, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int64[] left, Int64[] right, Int64[] result, [CallerMemberName] string method = "") + { + if ((long)(~left[0] & right[0]) != result[0]) + { + Succeeded = false; + } + else + { + for (var i = 1; i < left.Length; i++) + { + if ((long)(~left[i] & right[i]) != result[i]) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Sse2)}.{nameof(Sse2.AndNot)}<Int64>: {method} failed:"); + Console.WriteLine($" left: ({string.Join(", ", left)})"); + Console.WriteLine($" right: ({string.Join(", ", right)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/AndNot.SByte.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/AndNot.SByte.cs new file mode 100644 index 0000000000..0082496555 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/AndNot.SByte.cs @@ -0,0 +1,315 @@ +// 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 AndNotSByte() + { + var test = new SimpleBinaryOpTest__AndNotSByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + // 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(); + + // 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(); + + // 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 works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + 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__AndNotSByte + { + private const int VectorSize = 16; + private const int ElementCount = VectorSize / sizeof(SByte); + + private static SByte[] _data1 = new SByte[ElementCount]; + private static SByte[] _data2 = new SByte[ElementCount]; + + private static Vector128<SByte> _clsVar1; + private static Vector128<SByte> _clsVar2; + + private Vector128<SByte> _fld1; + private Vector128<SByte> _fld2; + + private SimpleBinaryOpTest__DataTable<SByte> _dataTable; + + static SimpleBinaryOpTest__AndNotSByte() + { + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue)); _data2[i] = (sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<SByte>, byte>(ref _clsVar1), ref Unsafe.As<SByte, byte>(ref _data2[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<SByte>, byte>(ref _clsVar2), ref Unsafe.As<SByte, byte>(ref _data1[0]), VectorSize); + } + + public SimpleBinaryOpTest__AndNotSByte() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue)); _data2[i] = (sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<SByte>, byte>(ref _fld1), ref Unsafe.As<SByte, byte>(ref _data1[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<SByte>, byte>(ref _fld2), ref Unsafe.As<SByte, byte>(ref _data2[0]), VectorSize); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue)); _data2[i] = (sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue)); } + _dataTable = new SimpleBinaryOpTest__DataTable<SByte>(_data1, _data2, new SByte[ElementCount], VectorSize); + } + + public bool IsSupported => Sse2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse2.AndNot( + Unsafe.Read<Vector128<SByte>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<SByte>>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse2.AndNot( + Sse2.LoadVector128((SByte*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((SByte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse2.AndNot( + Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.AndNot), new Type[] { typeof(Vector128<SByte>), typeof(Vector128<SByte>) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector128<SByte>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<SByte>>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<SByte>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.AndNot), new Type[] { typeof(Vector128<SByte>), typeof(Vector128<SByte>) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((SByte*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((SByte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<SByte>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.AndNot), new Type[] { typeof(Vector128<SByte>), typeof(Vector128<SByte>) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<SByte>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse2.AndNot( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read<Vector128<SByte>>(_dataTable.inArray1Ptr); + var right = Unsafe.Read<Vector128<SByte>>(_dataTable.inArray2Ptr); + var result = Sse2.AndNot(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((SByte*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((SByte*)(_dataTable.inArray2Ptr)); + var result = Sse2.AndNot(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArray2Ptr)); + var result = Sse2.AndNot(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__AndNotSByte(); + var result = Sse2.AndNot(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse2.AndNot(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128<SByte> left, Vector128<SByte> right, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[ElementCount]; + SByte[] inArray2 = new SByte[ElementCount]; + SByte[] outArray = new SByte[ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<SByte, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[ElementCount]; + SByte[] inArray2 = new SByte[ElementCount]; + SByte[] outArray = new SByte[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<SByte, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<SByte, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<SByte, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(SByte[] left, SByte[] right, SByte[] result, [CallerMemberName] string method = "") + { + if ((sbyte)(~left[0] & right[0]) != result[0]) + { + Succeeded = false; + } + else + { + for (var i = 1; i < left.Length; i++) + { + if ((sbyte)(~left[i] & right[i]) != result[i]) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Sse2)}.{nameof(Sse2.AndNot)}<SByte>: {method} failed:"); + Console.WriteLine($" left: ({string.Join(", ", left)})"); + Console.WriteLine($" right: ({string.Join(", ", right)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/AndNot.UInt16.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/AndNot.UInt16.cs new file mode 100644 index 0000000000..ab2ed5f277 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/AndNot.UInt16.cs @@ -0,0 +1,315 @@ +// 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 AndNotUInt16() + { + var test = new SimpleBinaryOpTest__AndNotUInt16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + // 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(); + + // 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(); + + // 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 works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + 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__AndNotUInt16 + { + private const int VectorSize = 16; + private const int ElementCount = VectorSize / sizeof(UInt16); + + private static UInt16[] _data1 = new UInt16[ElementCount]; + private static UInt16[] _data2 = new UInt16[ElementCount]; + + private static Vector128<UInt16> _clsVar1; + private static Vector128<UInt16> _clsVar2; + + private Vector128<UInt16> _fld1; + private Vector128<UInt16> _fld2; + + private SimpleBinaryOpTest__DataTable<UInt16> _dataTable; + + static SimpleBinaryOpTest__AndNotUInt16() + { + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (ushort)(random.Next(0, ushort.MaxValue)); _data2[i] = (ushort)(random.Next(0, ushort.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt16>, byte>(ref _clsVar1), ref Unsafe.As<UInt16, byte>(ref _data2[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt16>, byte>(ref _clsVar2), ref Unsafe.As<UInt16, byte>(ref _data1[0]), VectorSize); + } + + public SimpleBinaryOpTest__AndNotUInt16() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (ushort)(random.Next(0, ushort.MaxValue)); _data2[i] = (ushort)(random.Next(0, ushort.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt16>, byte>(ref _fld1), ref Unsafe.As<UInt16, byte>(ref _data1[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt16>, byte>(ref _fld2), ref Unsafe.As<UInt16, byte>(ref _data2[0]), VectorSize); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (ushort)(random.Next(0, ushort.MaxValue)); _data2[i] = (ushort)(random.Next(0, ushort.MaxValue)); } + _dataTable = new SimpleBinaryOpTest__DataTable<UInt16>(_data1, _data2, new UInt16[ElementCount], VectorSize); + } + + public bool IsSupported => Sse2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse2.AndNot( + Unsafe.Read<Vector128<UInt16>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<UInt16>>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse2.AndNot( + Sse2.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse2.AndNot( + Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.AndNot), new Type[] { typeof(Vector128<UInt16>), typeof(Vector128<UInt16>) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector128<UInt16>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<UInt16>>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<UInt16>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.AndNot), new Type[] { typeof(Vector128<UInt16>), typeof(Vector128<UInt16>) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<UInt16>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.AndNot), new Type[] { typeof(Vector128<UInt16>), typeof(Vector128<UInt16>) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<UInt16>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse2.AndNot( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read<Vector128<UInt16>>(_dataTable.inArray1Ptr); + var right = Unsafe.Read<Vector128<UInt16>>(_dataTable.inArray2Ptr); + var result = Sse2.AndNot(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)); + var result = Sse2.AndNot(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArray2Ptr)); + var result = Sse2.AndNot(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__AndNotUInt16(); + var result = Sse2.AndNot(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse2.AndNot(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128<UInt16> left, Vector128<UInt16> right, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[ElementCount]; + UInt16[] inArray2 = new UInt16[ElementCount]; + UInt16[] outArray = new UInt16[ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt16, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[ElementCount]; + UInt16[] inArray2 = new UInt16[ElementCount]; + UInt16[] outArray = new UInt16[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt16, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt16, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt16, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt16[] left, UInt16[] right, UInt16[] result, [CallerMemberName] string method = "") + { + if ((ushort)(~left[0] & right[0]) != result[0]) + { + Succeeded = false; + } + else + { + for (var i = 1; i < left.Length; i++) + { + if ((ushort)(~left[i] & right[i]) != result[i]) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Sse2)}.{nameof(Sse2.AndNot)}<UInt16>: {method} failed:"); + Console.WriteLine($" left: ({string.Join(", ", left)})"); + Console.WriteLine($" right: ({string.Join(", ", right)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/AndNot.UInt32.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/AndNot.UInt32.cs new file mode 100644 index 0000000000..6f87e8757e --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/AndNot.UInt32.cs @@ -0,0 +1,315 @@ +// 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 AndNotUInt32() + { + var test = new SimpleBinaryOpTest__AndNotUInt32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + // 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(); + + // 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(); + + // 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 works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + 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__AndNotUInt32 + { + private const int VectorSize = 16; + private const int ElementCount = VectorSize / sizeof(UInt32); + + private static UInt32[] _data1 = new UInt32[ElementCount]; + private static UInt32[] _data2 = new UInt32[ElementCount]; + + private static Vector128<UInt32> _clsVar1; + private static Vector128<UInt32> _clsVar2; + + private Vector128<UInt32> _fld1; + private Vector128<UInt32> _fld2; + + private SimpleBinaryOpTest__DataTable<UInt32> _dataTable; + + static SimpleBinaryOpTest__AndNotUInt32() + { + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (uint)(random.Next(0, int.MaxValue)); _data2[i] = (uint)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt32>, byte>(ref _clsVar1), ref Unsafe.As<UInt32, byte>(ref _data2[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt32>, byte>(ref _clsVar2), ref Unsafe.As<UInt32, byte>(ref _data1[0]), VectorSize); + } + + public SimpleBinaryOpTest__AndNotUInt32() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (uint)(random.Next(0, int.MaxValue)); _data2[i] = (uint)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt32>, byte>(ref _fld1), ref Unsafe.As<UInt32, byte>(ref _data1[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt32>, byte>(ref _fld2), ref Unsafe.As<UInt32, byte>(ref _data2[0]), VectorSize); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (uint)(random.Next(0, int.MaxValue)); _data2[i] = (uint)(random.Next(0, int.MaxValue)); } + _dataTable = new SimpleBinaryOpTest__DataTable<UInt32>(_data1, _data2, new UInt32[ElementCount], VectorSize); + } + + public bool IsSupported => Sse2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse2.AndNot( + Unsafe.Read<Vector128<UInt32>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<UInt32>>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse2.AndNot( + Sse2.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse2.AndNot( + Sse2.LoadAlignedVector128((UInt32*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((UInt32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.AndNot), new Type[] { typeof(Vector128<UInt32>), typeof(Vector128<UInt32>) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector128<UInt32>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<UInt32>>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<UInt32>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.AndNot), new Type[] { typeof(Vector128<UInt32>), typeof(Vector128<UInt32>) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<UInt32>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.AndNot), new Type[] { typeof(Vector128<UInt32>), typeof(Vector128<UInt32>) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((UInt32*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((UInt32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<UInt32>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse2.AndNot( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read<Vector128<UInt32>>(_dataTable.inArray1Ptr); + var right = Unsafe.Read<Vector128<UInt32>>(_dataTable.inArray2Ptr); + var result = Sse2.AndNot(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)); + var result = Sse2.AndNot(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((UInt32*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((UInt32*)(_dataTable.inArray2Ptr)); + var result = Sse2.AndNot(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__AndNotUInt32(); + var result = Sse2.AndNot(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse2.AndNot(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128<UInt32> left, Vector128<UInt32> right, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[ElementCount]; + UInt32[] inArray2 = new UInt32[ElementCount]; + UInt32[] outArray = new UInt32[ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt32, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[ElementCount]; + UInt32[] inArray2 = new UInt32[ElementCount]; + UInt32[] outArray = new UInt32[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt32, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt32, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt32, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt32[] left, UInt32[] right, UInt32[] result, [CallerMemberName] string method = "") + { + if ((uint)(~left[0] & right[0]) != result[0]) + { + Succeeded = false; + } + else + { + for (var i = 1; i < left.Length; i++) + { + if ((uint)(~left[i] & right[i]) != result[i]) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Sse2)}.{nameof(Sse2.AndNot)}<UInt32>: {method} failed:"); + Console.WriteLine($" left: ({string.Join(", ", left)})"); + Console.WriteLine($" right: ({string.Join(", ", right)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/AndNot.UInt64.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/AndNot.UInt64.cs new file mode 100644 index 0000000000..64d975b4f5 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/AndNot.UInt64.cs @@ -0,0 +1,315 @@ +// 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 AndNotUInt64() + { + var test = new SimpleBinaryOpTest__AndNotUInt64(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + // 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(); + + // 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(); + + // 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 works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + 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__AndNotUInt64 + { + private const int VectorSize = 16; + private const int ElementCount = VectorSize / sizeof(UInt64); + + private static UInt64[] _data1 = new UInt64[ElementCount]; + private static UInt64[] _data2 = new UInt64[ElementCount]; + + private static Vector128<UInt64> _clsVar1; + private static Vector128<UInt64> _clsVar2; + + private Vector128<UInt64> _fld1; + private Vector128<UInt64> _fld2; + + private SimpleBinaryOpTest__DataTable<UInt64> _dataTable; + + static SimpleBinaryOpTest__AndNotUInt64() + { + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (ulong)(random.Next(0, int.MaxValue)); _data2[i] = (ulong)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt64>, byte>(ref _clsVar1), ref Unsafe.As<UInt64, byte>(ref _data2[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt64>, byte>(ref _clsVar2), ref Unsafe.As<UInt64, byte>(ref _data1[0]), VectorSize); + } + + public SimpleBinaryOpTest__AndNotUInt64() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (ulong)(random.Next(0, int.MaxValue)); _data2[i] = (ulong)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt64>, byte>(ref _fld1), ref Unsafe.As<UInt64, byte>(ref _data1[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt64>, byte>(ref _fld2), ref Unsafe.As<UInt64, byte>(ref _data2[0]), VectorSize); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (ulong)(random.Next(0, int.MaxValue)); _data2[i] = (ulong)(random.Next(0, int.MaxValue)); } + _dataTable = new SimpleBinaryOpTest__DataTable<UInt64>(_data1, _data2, new UInt64[ElementCount], VectorSize); + } + + public bool IsSupported => Sse2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse2.AndNot( + Unsafe.Read<Vector128<UInt64>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<UInt64>>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse2.AndNot( + Sse2.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((UInt64*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse2.AndNot( + Sse2.LoadAlignedVector128((UInt64*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((UInt64*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.AndNot), new Type[] { typeof(Vector128<UInt64>), typeof(Vector128<UInt64>) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector128<UInt64>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<UInt64>>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<UInt64>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.AndNot), new Type[] { typeof(Vector128<UInt64>), typeof(Vector128<UInt64>) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((UInt64*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<UInt64>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.AndNot), new Type[] { typeof(Vector128<UInt64>), typeof(Vector128<UInt64>) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((UInt64*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((UInt64*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<UInt64>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse2.AndNot( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read<Vector128<UInt64>>(_dataTable.inArray1Ptr); + var right = Unsafe.Read<Vector128<UInt64>>(_dataTable.inArray2Ptr); + var result = Sse2.AndNot(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((UInt64*)(_dataTable.inArray2Ptr)); + var result = Sse2.AndNot(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((UInt64*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((UInt64*)(_dataTable.inArray2Ptr)); + var result = Sse2.AndNot(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__AndNotUInt64(); + var result = Sse2.AndNot(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse2.AndNot(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128<UInt64> left, Vector128<UInt64> right, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray1 = new UInt64[ElementCount]; + UInt64[] inArray2 = new UInt64[ElementCount]; + UInt64[] outArray = new UInt64[ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt64, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray1 = new UInt64[ElementCount]; + UInt64[] inArray2 = new UInt64[ElementCount]; + UInt64[] outArray = new UInt64[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt64, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt64, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt64, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt64[] left, UInt64[] right, UInt64[] result, [CallerMemberName] string method = "") + { + if ((ulong)(~left[0] & right[0]) != result[0]) + { + Succeeded = false; + } + else + { + for (var i = 1; i < left.Length; i++) + { + if ((ulong)(~left[i] & right[i]) != result[i]) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Sse2)}.{nameof(Sse2.AndNot)}<UInt64>: {method} failed:"); + Console.WriteLine($" left: ({string.Join(", ", left)})"); + Console.WriteLine($" right: ({string.Join(", ", right)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/AndNot.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/AndNot.cs deleted file mode 100644 index a757419f6f..0000000000 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/AndNot.cs +++ /dev/null @@ -1,187 +0,0 @@ -// 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. -// - -using System; -using System.Runtime.Intrinsics; -using System.Runtime.Intrinsics.X86; - -namespace IntelHardwareIntrinsicTest -{ - internal static partial class Program - { - const int Pass = 100; - const int Fail = 0; - - static unsafe int Main(string[] args) - { - int testResult = Pass; - int testsCount = 21; - string methodUnderTestName = nameof(Sse2.AndNot); - - if (Sse2.IsSupported) - { - using (var doubleTable = TestTableSse2<double>.Create(testsCount)) - using (var longTable = TestTableSse2<long>.Create(testsCount)) - using (var ulongTable = TestTableSse2<ulong>.Create(testsCount)) - using (var intTable = TestTableSse2<int>.Create(testsCount)) - using (var uintTable = TestTableSse2<uint>.Create(testsCount)) - using (var shortTable = TestTableSse2<short>.Create(testsCount)) - using (var ushortTable = TestTableSse2<ushort>.Create(testsCount)) - using (var sbyteTable = TestTableSse2<sbyte>.Create(testsCount)) - using (var byteTable = TestTableSse2<byte>.Create(testsCount)) - { - for (int i = 0; i < testsCount; i++) - { - (Vector128<double>, Vector128<double>, Vector128<double>) value = doubleTable[i]; - var result = Sse2.AndNot(value.Item1, value.Item2); - doubleTable.SetOutArray(result); - } - - for (int i = 0; i < testsCount; i++) - { - (Vector128<long>, Vector128<long>, Vector128<long>) value = longTable[i]; - var result = Sse2.AndNot(value.Item1, value.Item2); - longTable.SetOutArray(result); - } - - for (int i = 0; i < testsCount; i++) - { - (Vector128<ulong>, Vector128<ulong>, Vector128<ulong>) value = ulongTable[i]; - var result = Sse2.AndNot(value.Item1, value.Item2); - ulongTable.SetOutArray(result); - } - - for (int i = 0; i < testsCount; i++) - { - (Vector128<int>, Vector128<int>, Vector128<int>) value = intTable[i]; - var result = Sse2.AndNot(value.Item1, value.Item2); - intTable.SetOutArray(result); - } - - for (int i = 0; i < testsCount; i++) - { - (Vector128<uint>, Vector128<uint>, Vector128<uint>) value = uintTable[i]; - var result = Sse2.AndNot(value.Item1, value.Item2); - uintTable.SetOutArray(result); - } - - for (int i = 0; i < testsCount; i++) - { - (Vector128<short>, Vector128<short>, Vector128<short>) value = shortTable[i]; - var result = Sse2.AndNot(value.Item1, value.Item2); - shortTable.SetOutArray(result); - } - - for (int i = 0; i < testsCount; i++) - { - (Vector128<ushort>, Vector128<ushort>, Vector128<ushort>) value = ushortTable[i]; - var result = Sse2.AndNot(value.Item1, value.Item2); - ushortTable.SetOutArray(result); - } - - for (int i = 0; i < testsCount; i++) - { - (Vector128<sbyte>, Vector128<sbyte>, Vector128<sbyte>) value = sbyteTable[i]; - var result = Sse2.AndNot(value.Item1, value.Item2); - sbyteTable.SetOutArray(result); - } - - for (int i = 0; i < testsCount; i++) - { - (Vector128<byte>, Vector128<byte>, Vector128<byte>) value = byteTable[i]; - var result = Sse2.AndNot(value.Item1, value.Item2); - byteTable.SetOutArray(result); - } - - CheckMethod<double> checkDouble = (double x, double y, double z, ref double a) => (a = BinaryAndNot(x, y)) == z; - - if (!doubleTable.CheckResult(checkDouble)) - { - PrintError(doubleTable, methodUnderTestName, "(double x, double y, double z, ref double a) => (a = BinaryAndNot(x, y)) == z", checkDouble); - testResult = Fail; - } - - CheckMethod<long> checkLong = (long x, long y, long z, ref long a) => (a = (~x) & y) == z; - - if (!longTable.CheckResult(checkLong)) - { - PrintError(longTable, methodUnderTestName, "(long x, long y, long z, ref long a) => (a = (~x) & y) == z", checkLong); - testResult = Fail; - } - - CheckMethod<ulong> checkUlong = (ulong x, ulong y, ulong z, ref ulong a) => (a = (~x) & y) == z; - - if (!longTable.CheckResult(checkLong)) - { - PrintError(ulongTable, methodUnderTestName, "(ulong x, ulong y, ulong z, ref ulong a) => (a = (~x) & y) == z", checkUlong); - testResult = Fail; - } - - CheckMethod<int> checkInt32 = (int x, int y, int z, ref int a) => (a = (~x) & y) == z; - - if (!intTable.CheckResult(checkInt32)) - { - PrintError(intTable, methodUnderTestName, "(int x, int y, int z, ref int a) => (a = (~x) & y) == z", checkInt32); - testResult = Fail; - } - - CheckMethod<uint> checkUInt32 = (uint x, uint y, uint z, ref uint a) => (a = (~x) & y) == z; - - if (!uintTable.CheckResult(checkUInt32)) - { - PrintError(uintTable, methodUnderTestName, "(uint x, uint y, uint z, ref uint a) => (a = (~x) & y) == z", checkUInt32); - testResult = Fail; - } - - CheckMethod<short> checkInt16 = (short x, short y, short z, ref short a) => (a = (short)((~x) & y)) == z; - - if (!shortTable.CheckResult(checkInt16)) - { - PrintError(shortTable, methodUnderTestName, "(short x, short y, short z, ref short a) => (a = (short)((~x) & y)) == z", checkInt16); - testResult = Fail; - } - - CheckMethod<ushort> checkUInt16 = (ushort x, ushort y, ushort z, ref ushort a) => (a = (ushort)((~x) & y)) == z; - - if (!ushortTable.CheckResult(checkUInt16)) - { - PrintError(ushortTable, methodUnderTestName, "(ushort x, ushort y, ushort z, ref ushort a) => (a = (ushort)((~x) & y)) == z", checkUInt16); - testResult = Fail; - } - - CheckMethod<sbyte> checkSByte = (sbyte x, sbyte y, sbyte z, ref sbyte a) => (a = (sbyte)((~x) & y)) == z; - - if (!sbyteTable.CheckResult(checkSByte)) - { - PrintError(sbyteTable, methodUnderTestName, "(sbyte x, sbyte y, sbyte z, ref sbyte a) =>(a = (sbyte)((~x) & y)) == z", checkSByte); - testResult = Fail; - } - - CheckMethod<byte> checkByte = (byte x, byte y, byte z, ref byte a) => (a = (byte)((~x) & y)) == z; - - if (!byteTable.CheckResult(checkByte)) - { - PrintError(byteTable, methodUnderTestName, "(byte x, byte y, byte z, ref byte a) => (a = (byte)((~x) & y)) == z", checkByte); - testResult = Fail; - } - } - } - else - { - Console.WriteLine($"Sse2.IsSupported: {Sse2.IsSupported}, skipped tests of {typeof(Sse2)}.{methodUnderTestName}"); - } - - return testResult; - } - - public static double BinaryAndNot(double x, double y) - { - var xLong = BitConverter.ToInt64(BitConverter.GetBytes(x)); - var yLong = BitConverter.ToInt64(BitConverter.GetBytes(y)); - xLong = ((~xLong) & yLong); - return BitConverter.ToDouble(BitConverter.GetBytes(xLong)); - } - } -} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/AndNot_r.csproj b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/AndNot_r.csproj deleted file mode 100644 index 0b2fce0a87..0000000000 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/AndNot_r.csproj +++ /dev/null @@ -1,41 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" /> - <PropertyGroup> - <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> - <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> - <SchemaVersion>2.0</SchemaVersion> - <ProjectGuid>{1FEAE9EB-3D81-4367-8B88-91348178128D}</ProjectGuid> - <OutputType>Exe</OutputType> - <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> - <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir> - <AllowUnsafeBlocks>true</AllowUnsafeBlocks> - </PropertyGroup> - <!-- Default configurations to help VS understand the configurations --> - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> - </PropertyGroup> - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' " /> - <ItemGroup> - <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies"> - <Visible>False</Visible> - </CodeAnalysisDependentAssemblyPaths> - </ItemGroup> - <PropertyGroup> - <DebugType>None</DebugType> - <Optimize> - </Optimize> - </PropertyGroup> - <PropertyGroup> - <LangVersion>7.1</LangVersion> - </PropertyGroup> - <ItemGroup> - <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" /> - </ItemGroup> - <ItemGroup> - <Compile Include="AndNot.cs" /> - <Compile Include="TestTableSse2.cs" /> - </ItemGroup> - <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" /> - <PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' "> - </PropertyGroup> -</Project>
\ No newline at end of file diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/AndNot_ro.csproj b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/AndNot_ro.csproj deleted file mode 100644 index 72b237b743..0000000000 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/AndNot_ro.csproj +++ /dev/null @@ -1,37 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" /> - <PropertyGroup> - <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> - <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> - <SchemaVersion>2.0</SchemaVersion> - <ProjectGuid>{39F85E0C-902F-4426-B91D-5190B280A7F5}</ProjectGuid> - <OutputType>Exe</OutputType> - <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> - <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir> - <AllowUnsafeBlocks>true</AllowUnsafeBlocks> - </PropertyGroup> - <!-- Default configurations to help VS understand the configurations --> - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> - </PropertyGroup> - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' " /> - <ItemGroup> - <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies"> - <Visible>False</Visible> - </CodeAnalysisDependentAssemblyPaths> - </ItemGroup> - <PropertyGroup> - <DebugType>None</DebugType> - <Optimize>True</Optimize> - </PropertyGroup> - <ItemGroup> - <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" /> - </ItemGroup> - <ItemGroup> - <Compile Include="AndNot.cs" /> - <Compile Include="TestTableSse2.cs" /> - </ItemGroup> - <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" /> - <PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' "> - </PropertyGroup> -</Project>
\ No newline at end of file diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/And_r.csproj b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/And_r.csproj deleted file mode 100644 index c5983931a8..0000000000 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/And_r.csproj +++ /dev/null @@ -1,38 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" /> - <PropertyGroup> - <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> - <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> - <SchemaVersion>2.0</SchemaVersion> - <ProjectGuid>{95DFC527-4DC1-495E-97D7-E94EE1F7140D}</ProjectGuid> - <OutputType>Exe</OutputType> - <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> - <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir> - <AllowUnsafeBlocks>true</AllowUnsafeBlocks> - </PropertyGroup> - <!-- Default configurations to help VS understand the configurations --> - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> - </PropertyGroup> - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' " /> - <ItemGroup> - <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies"> - <Visible>False</Visible> - </CodeAnalysisDependentAssemblyPaths> - </ItemGroup> - <PropertyGroup> - <DebugType>None</DebugType> - <Optimize> - </Optimize> - </PropertyGroup> - <ItemGroup> - <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" /> - </ItemGroup> - <ItemGroup> - <Compile Include="And.cs" /> - <Compile Include="TestTableSse2.cs" /> - </ItemGroup> - <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" /> - <PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' "> - </PropertyGroup> -</Project>
\ No newline at end of file diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/And_ro.csproj b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/And_ro.csproj deleted file mode 100644 index 49cb64ba34..0000000000 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/And_ro.csproj +++ /dev/null @@ -1,37 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" /> - <PropertyGroup> - <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> - <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> - <SchemaVersion>2.0</SchemaVersion> - <ProjectGuid>{76498BB3-401E-45B1-8A11-818B392E2003}</ProjectGuid> - <OutputType>Exe</OutputType> - <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> - <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir> - <AllowUnsafeBlocks>true</AllowUnsafeBlocks> - </PropertyGroup> - <!-- Default configurations to help VS understand the configurations --> - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> - </PropertyGroup> - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' " /> - <ItemGroup> - <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies"> - <Visible>False</Visible> - </CodeAnalysisDependentAssemblyPaths> - </ItemGroup> - <PropertyGroup> - <DebugType>None</DebugType> - <Optimize>True</Optimize> - </PropertyGroup> - <ItemGroup> - <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" /> - </ItemGroup> - <ItemGroup> - <Compile Include="And.cs" /> - <Compile Include="TestTableSse2.cs" /> - </ItemGroup> - <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" /> - <PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' "> - </PropertyGroup> -</Project>
\ No newline at end of file diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareEqual.Byte.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareEqual.Byte.cs new file mode 100644 index 0000000000..a97e76c268 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareEqual.Byte.cs @@ -0,0 +1,315 @@ +// 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 CompareEqualByte() + { + var test = new SimpleBinaryOpTest__CompareEqualByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + // 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(); + + // 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(); + + // 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 works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + 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__CompareEqualByte + { + private const int VectorSize = 16; + private const int ElementCount = VectorSize / sizeof(Byte); + + private static Byte[] _data1 = new Byte[ElementCount]; + private static Byte[] _data2 = new Byte[ElementCount]; + + private static Vector128<Byte> _clsVar1; + private static Vector128<Byte> _clsVar2; + + private Vector128<Byte> _fld1; + private Vector128<Byte> _fld2; + + private SimpleBinaryOpTest__DataTable<Byte> _dataTable; + + static SimpleBinaryOpTest__CompareEqualByte() + { + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (byte)(random.Next(0, byte.MaxValue)); _data2[i] = (byte)(random.Next(0, byte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Byte>, byte>(ref _clsVar1), ref Unsafe.As<Byte, byte>(ref _data2[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Byte>, byte>(ref _clsVar2), ref Unsafe.As<Byte, byte>(ref _data1[0]), VectorSize); + } + + public SimpleBinaryOpTest__CompareEqualByte() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (byte)(random.Next(0, byte.MaxValue)); _data2[i] = (byte)(random.Next(0, byte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Byte>, byte>(ref _fld1), ref Unsafe.As<Byte, byte>(ref _data1[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Byte>, byte>(ref _fld2), ref Unsafe.As<Byte, byte>(ref _data2[0]), VectorSize); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (byte)(random.Next(0, byte.MaxValue)); _data2[i] = (byte)(random.Next(0, byte.MaxValue)); } + _dataTable = new SimpleBinaryOpTest__DataTable<Byte>(_data1, _data2, new Byte[ElementCount], VectorSize); + } + + public bool IsSupported => Sse2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse2.CompareEqual( + Unsafe.Read<Vector128<Byte>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<Byte>>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse2.CompareEqual( + Sse2.LoadVector128((Byte*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Byte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse2.CompareEqual( + Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.CompareEqual), new Type[] { typeof(Vector128<Byte>), typeof(Vector128<Byte>) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector128<Byte>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<Byte>>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Byte>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.CompareEqual), new Type[] { typeof(Vector128<Byte>), typeof(Vector128<Byte>) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Byte*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Byte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Byte>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.CompareEqual), new Type[] { typeof(Vector128<Byte>), typeof(Vector128<Byte>) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Byte>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse2.CompareEqual( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read<Vector128<Byte>>(_dataTable.inArray1Ptr); + var right = Unsafe.Read<Vector128<Byte>>(_dataTable.inArray2Ptr); + var result = Sse2.CompareEqual(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((Byte*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((Byte*)(_dataTable.inArray2Ptr)); + var result = Sse2.CompareEqual(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray2Ptr)); + var result = Sse2.CompareEqual(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__CompareEqualByte(); + var result = Sse2.CompareEqual(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse2.CompareEqual(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128<Byte> left, Vector128<Byte> right, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[ElementCount]; + Byte[] inArray2 = new Byte[ElementCount]; + Byte[] outArray = new Byte[ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Byte, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[ElementCount]; + Byte[] inArray2 = new Byte[ElementCount]; + Byte[] outArray = new Byte[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Byte, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Byte, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Byte, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Byte[] left, Byte[] right, Byte[] result, [CallerMemberName] string method = "") + { + if (result[0] != ((left[0] == right[0]) ? unchecked((byte)(-1)) : 0)) + { + Succeeded = false; + } + else + { + for (var i = 1; i < left.Length; i++) + { + if (result[i] != ((left[i] == right[i]) ? unchecked((byte)(-1)) : 0)) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Sse2)}.{nameof(Sse2.CompareEqual)}<Byte>: {method} failed:"); + Console.WriteLine($" left: ({string.Join(", ", left)})"); + Console.WriteLine($" right: ({string.Join(", ", right)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareEqual.Double.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareEqual.Double.cs new file mode 100644 index 0000000000..8f2305cc5b --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareEqual.Double.cs @@ -0,0 +1,315 @@ +// 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 CompareEqualDouble() + { + var test = new SimpleBinaryOpTest__CompareEqualDouble(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + // 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(); + + // 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(); + + // 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 works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + 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__CompareEqualDouble + { + private const int VectorSize = 16; + private const int ElementCount = VectorSize / sizeof(Double); + + private static Double[] _data1 = new Double[ElementCount]; + private static Double[] _data2 = new Double[ElementCount]; + + private static Vector128<Double> _clsVar1; + private static Vector128<Double> _clsVar2; + + private Vector128<Double> _fld1; + private Vector128<Double> _fld2; + + private SimpleBinaryOpTest__DataTable<Double> _dataTable; + + static SimpleBinaryOpTest__CompareEqualDouble() + { + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (double)(random.NextDouble()); _data2[i] = (double)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Double>, byte>(ref _clsVar1), ref Unsafe.As<Double, byte>(ref _data2[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Double>, byte>(ref _clsVar2), ref Unsafe.As<Double, byte>(ref _data1[0]), VectorSize); + } + + public SimpleBinaryOpTest__CompareEqualDouble() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (double)(random.NextDouble()); _data2[i] = (double)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Double>, byte>(ref _fld1), ref Unsafe.As<Double, byte>(ref _data1[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Double>, byte>(ref _fld2), ref Unsafe.As<Double, byte>(ref _data2[0]), VectorSize); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (double)(random.NextDouble()); _data2[i] = (double)(random.NextDouble()); } + _dataTable = new SimpleBinaryOpTest__DataTable<Double>(_data1, _data2, new Double[ElementCount], VectorSize); + } + + public bool IsSupported => Sse2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse2.CompareEqual( + Unsafe.Read<Vector128<Double>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<Double>>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse2.CompareEqual( + Sse2.LoadVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Double*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse2.CompareEqual( + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.CompareEqual), new Type[] { typeof(Vector128<Double>), typeof(Vector128<Double>) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector128<Double>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<Double>>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Double>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.CompareEqual), new Type[] { typeof(Vector128<Double>), typeof(Vector128<Double>) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Double*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Double>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.CompareEqual), new Type[] { typeof(Vector128<Double>), typeof(Vector128<Double>) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Double>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse2.CompareEqual( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read<Vector128<Double>>(_dataTable.inArray1Ptr); + var right = Unsafe.Read<Vector128<Double>>(_dataTable.inArray2Ptr); + var result = Sse2.CompareEqual(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((Double*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((Double*)(_dataTable.inArray2Ptr)); + var result = Sse2.CompareEqual(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray2Ptr)); + var result = Sse2.CompareEqual(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__CompareEqualDouble(); + var result = Sse2.CompareEqual(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse2.CompareEqual(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128<Double> left, Vector128<Double> right, void* result, [CallerMemberName] string method = "") + { + Double[] inArray1 = new Double[ElementCount]; + Double[] inArray2 = new Double[ElementCount]; + Double[] outArray = new Double[ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Double[] inArray1 = new Double[ElementCount]; + Double[] inArray2 = new Double[ElementCount]; + Double[] outArray = new Double[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Double[] left, Double[] right, Double[] result, [CallerMemberName] string method = "") + { + if (BitConverter.DoubleToInt64Bits(result[0]) != ((left[0] == right[0]) ? -1 : 0)) + { + Succeeded = false; + } + else + { + for (var i = 1; i < left.Length; i++) + { + if (BitConverter.DoubleToInt64Bits(result[i]) != ((left[i] == right[i]) ? -1 : 0)) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Sse2)}.{nameof(Sse2.CompareEqual)}<Double>: {method} failed:"); + Console.WriteLine($" left: ({string.Join(", ", left)})"); + Console.WriteLine($" right: ({string.Join(", ", right)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareEqual.Int16.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareEqual.Int16.cs new file mode 100644 index 0000000000..567cecb4f7 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareEqual.Int16.cs @@ -0,0 +1,315 @@ +// 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 CompareEqualInt16() + { + var test = new SimpleBinaryOpTest__CompareEqualInt16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + // 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(); + + // 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(); + + // 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 works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + 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__CompareEqualInt16 + { + private const int VectorSize = 16; + private const int ElementCount = VectorSize / sizeof(Int16); + + private static Int16[] _data1 = new Int16[ElementCount]; + private static Int16[] _data2 = new Int16[ElementCount]; + + private static Vector128<Int16> _clsVar1; + private static Vector128<Int16> _clsVar2; + + private Vector128<Int16> _fld1; + private Vector128<Int16> _fld2; + + private SimpleBinaryOpTest__DataTable<Int16> _dataTable; + + static SimpleBinaryOpTest__CompareEqualInt16() + { + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (short)(random.Next(short.MinValue, short.MaxValue)); _data2[i] = (short)(random.Next(short.MinValue, short.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int16>, byte>(ref _clsVar1), ref Unsafe.As<Int16, byte>(ref _data2[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int16>, byte>(ref _clsVar2), ref Unsafe.As<Int16, byte>(ref _data1[0]), VectorSize); + } + + public SimpleBinaryOpTest__CompareEqualInt16() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (short)(random.Next(short.MinValue, short.MaxValue)); _data2[i] = (short)(random.Next(short.MinValue, short.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int16>, byte>(ref _fld1), ref Unsafe.As<Int16, byte>(ref _data1[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int16>, byte>(ref _fld2), ref Unsafe.As<Int16, byte>(ref _data2[0]), VectorSize); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (short)(random.Next(short.MinValue, short.MaxValue)); _data2[i] = (short)(random.Next(short.MinValue, short.MaxValue)); } + _dataTable = new SimpleBinaryOpTest__DataTable<Int16>(_data1, _data2, new Int16[ElementCount], VectorSize); + } + + public bool IsSupported => Sse2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse2.CompareEqual( + Unsafe.Read<Vector128<Int16>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<Int16>>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse2.CompareEqual( + Sse2.LoadVector128((Int16*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Int16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse2.CompareEqual( + Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.CompareEqual), new Type[] { typeof(Vector128<Int16>), typeof(Vector128<Int16>) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector128<Int16>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<Int16>>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Int16>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.CompareEqual), new Type[] { typeof(Vector128<Int16>), typeof(Vector128<Int16>) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Int16*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Int16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Int16>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.CompareEqual), new Type[] { typeof(Vector128<Int16>), typeof(Vector128<Int16>) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Int16>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse2.CompareEqual( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read<Vector128<Int16>>(_dataTable.inArray1Ptr); + var right = Unsafe.Read<Vector128<Int16>>(_dataTable.inArray2Ptr); + var result = Sse2.CompareEqual(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((Int16*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((Int16*)(_dataTable.inArray2Ptr)); + var result = Sse2.CompareEqual(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray2Ptr)); + var result = Sse2.CompareEqual(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__CompareEqualInt16(); + var result = Sse2.CompareEqual(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse2.CompareEqual(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128<Int16> left, Vector128<Int16> right, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[ElementCount]; + Int16[] inArray2 = new Int16[ElementCount]; + Int16[] outArray = new Int16[ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int16, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[ElementCount]; + Int16[] inArray2 = new Int16[ElementCount]; + Int16[] outArray = new Int16[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int16, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int16, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int16, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int16[] left, Int16[] right, Int16[] result, [CallerMemberName] string method = "") + { + if (result[0] != ((left[0] == right[0]) ? unchecked((short)(-1)) : 0)) + { + Succeeded = false; + } + else + { + for (var i = 1; i < left.Length; i++) + { + if (result[i] != ((left[i] == right[i]) ? unchecked((short)(-1)) : 0)) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Sse2)}.{nameof(Sse2.CompareEqual)}<Int16>: {method} failed:"); + Console.WriteLine($" left: ({string.Join(", ", left)})"); + Console.WriteLine($" right: ({string.Join(", ", right)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareEqual.Int32.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareEqual.Int32.cs new file mode 100644 index 0000000000..7844d3f4e8 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareEqual.Int32.cs @@ -0,0 +1,315 @@ +// 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 CompareEqualInt32() + { + var test = new SimpleBinaryOpTest__CompareEqualInt32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + // 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(); + + // 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(); + + // 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 works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + 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__CompareEqualInt32 + { + private const int VectorSize = 16; + private const int ElementCount = VectorSize / sizeof(Int32); + + private static Int32[] _data1 = new Int32[ElementCount]; + private static Int32[] _data2 = new Int32[ElementCount]; + + private static Vector128<Int32> _clsVar1; + private static Vector128<Int32> _clsVar2; + + private Vector128<Int32> _fld1; + private Vector128<Int32> _fld2; + + private SimpleBinaryOpTest__DataTable<Int32> _dataTable; + + static SimpleBinaryOpTest__CompareEqualInt32() + { + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (int)(random.Next(int.MinValue, int.MaxValue)); _data2[i] = (int)(random.Next(int.MinValue, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int32>, byte>(ref _clsVar1), ref Unsafe.As<Int32, byte>(ref _data2[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int32>, byte>(ref _clsVar2), ref Unsafe.As<Int32, byte>(ref _data1[0]), VectorSize); + } + + public SimpleBinaryOpTest__CompareEqualInt32() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (int)(random.Next(int.MinValue, int.MaxValue)); _data2[i] = (int)(random.Next(int.MinValue, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int32>, byte>(ref _fld1), ref Unsafe.As<Int32, byte>(ref _data1[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int32>, byte>(ref _fld2), ref Unsafe.As<Int32, byte>(ref _data2[0]), VectorSize); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (int)(random.Next(int.MinValue, int.MaxValue)); _data2[i] = (int)(random.Next(int.MinValue, int.MaxValue)); } + _dataTable = new SimpleBinaryOpTest__DataTable<Int32>(_data1, _data2, new Int32[ElementCount], VectorSize); + } + + public bool IsSupported => Sse2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse2.CompareEqual( + Unsafe.Read<Vector128<Int32>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<Int32>>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse2.CompareEqual( + Sse2.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Int32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse2.CompareEqual( + Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.CompareEqual), new Type[] { typeof(Vector128<Int32>), typeof(Vector128<Int32>) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector128<Int32>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<Int32>>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Int32>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.CompareEqual), new Type[] { typeof(Vector128<Int32>), typeof(Vector128<Int32>) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Int32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Int32>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.CompareEqual), new Type[] { typeof(Vector128<Int32>), typeof(Vector128<Int32>) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Int32>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse2.CompareEqual( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read<Vector128<Int32>>(_dataTable.inArray1Ptr); + var right = Unsafe.Read<Vector128<Int32>>(_dataTable.inArray2Ptr); + var result = Sse2.CompareEqual(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((Int32*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((Int32*)(_dataTable.inArray2Ptr)); + var result = Sse2.CompareEqual(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray2Ptr)); + var result = Sse2.CompareEqual(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__CompareEqualInt32(); + var result = Sse2.CompareEqual(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse2.CompareEqual(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128<Int32> left, Vector128<Int32> right, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[ElementCount]; + Int32[] inArray2 = new Int32[ElementCount]; + Int32[] outArray = new Int32[ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int32, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[ElementCount]; + Int32[] inArray2 = new Int32[ElementCount]; + Int32[] outArray = new Int32[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int32, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int32, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int32, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int32[] left, Int32[] right, Int32[] result, [CallerMemberName] string method = "") + { + if (result[0] != ((left[0] == right[0]) ? unchecked((int)(-1)) : 0)) + { + Succeeded = false; + } + else + { + for (var i = 1; i < left.Length; i++) + { + if (result[i] != ((left[i] == right[i]) ? unchecked((int)(-1)) : 0)) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Sse2)}.{nameof(Sse2.CompareEqual)}<Int32>: {method} failed:"); + Console.WriteLine($" left: ({string.Join(", ", left)})"); + Console.WriteLine($" right: ({string.Join(", ", right)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareEqual.SByte.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareEqual.SByte.cs new file mode 100644 index 0000000000..55199d8902 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareEqual.SByte.cs @@ -0,0 +1,315 @@ +// 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 CompareEqualSByte() + { + var test = new SimpleBinaryOpTest__CompareEqualSByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + // 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(); + + // 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(); + + // 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 works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + 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__CompareEqualSByte + { + private const int VectorSize = 16; + private const int ElementCount = VectorSize / sizeof(SByte); + + private static SByte[] _data1 = new SByte[ElementCount]; + private static SByte[] _data2 = new SByte[ElementCount]; + + private static Vector128<SByte> _clsVar1; + private static Vector128<SByte> _clsVar2; + + private Vector128<SByte> _fld1; + private Vector128<SByte> _fld2; + + private SimpleBinaryOpTest__DataTable<SByte> _dataTable; + + static SimpleBinaryOpTest__CompareEqualSByte() + { + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue)); _data2[i] = (sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<SByte>, byte>(ref _clsVar1), ref Unsafe.As<SByte, byte>(ref _data2[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<SByte>, byte>(ref _clsVar2), ref Unsafe.As<SByte, byte>(ref _data1[0]), VectorSize); + } + + public SimpleBinaryOpTest__CompareEqualSByte() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue)); _data2[i] = (sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<SByte>, byte>(ref _fld1), ref Unsafe.As<SByte, byte>(ref _data1[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<SByte>, byte>(ref _fld2), ref Unsafe.As<SByte, byte>(ref _data2[0]), VectorSize); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue)); _data2[i] = (sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue)); } + _dataTable = new SimpleBinaryOpTest__DataTable<SByte>(_data1, _data2, new SByte[ElementCount], VectorSize); + } + + public bool IsSupported => Sse2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse2.CompareEqual( + Unsafe.Read<Vector128<SByte>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<SByte>>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse2.CompareEqual( + Sse2.LoadVector128((SByte*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((SByte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse2.CompareEqual( + Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.CompareEqual), new Type[] { typeof(Vector128<SByte>), typeof(Vector128<SByte>) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector128<SByte>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<SByte>>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<SByte>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.CompareEqual), new Type[] { typeof(Vector128<SByte>), typeof(Vector128<SByte>) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((SByte*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((SByte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<SByte>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.CompareEqual), new Type[] { typeof(Vector128<SByte>), typeof(Vector128<SByte>) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<SByte>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse2.CompareEqual( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read<Vector128<SByte>>(_dataTable.inArray1Ptr); + var right = Unsafe.Read<Vector128<SByte>>(_dataTable.inArray2Ptr); + var result = Sse2.CompareEqual(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((SByte*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((SByte*)(_dataTable.inArray2Ptr)); + var result = Sse2.CompareEqual(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArray2Ptr)); + var result = Sse2.CompareEqual(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__CompareEqualSByte(); + var result = Sse2.CompareEqual(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse2.CompareEqual(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128<SByte> left, Vector128<SByte> right, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[ElementCount]; + SByte[] inArray2 = new SByte[ElementCount]; + SByte[] outArray = new SByte[ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<SByte, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[ElementCount]; + SByte[] inArray2 = new SByte[ElementCount]; + SByte[] outArray = new SByte[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<SByte, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<SByte, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<SByte, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(SByte[] left, SByte[] right, SByte[] result, [CallerMemberName] string method = "") + { + if (result[0] != ((left[0] == right[0]) ? unchecked((sbyte)(-1)) : 0)) + { + Succeeded = false; + } + else + { + for (var i = 1; i < left.Length; i++) + { + if (result[i] != ((left[i] == right[i]) ? unchecked((sbyte)(-1)) : 0)) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Sse2)}.{nameof(Sse2.CompareEqual)}<SByte>: {method} failed:"); + Console.WriteLine($" left: ({string.Join(", ", left)})"); + Console.WriteLine($" right: ({string.Join(", ", right)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareEqual.UInt16.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareEqual.UInt16.cs new file mode 100644 index 0000000000..a61d1dc218 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareEqual.UInt16.cs @@ -0,0 +1,315 @@ +// 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 CompareEqualUInt16() + { + var test = new SimpleBinaryOpTest__CompareEqualUInt16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + // 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(); + + // 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(); + + // 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 works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + 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__CompareEqualUInt16 + { + private const int VectorSize = 16; + private const int ElementCount = VectorSize / sizeof(UInt16); + + private static UInt16[] _data1 = new UInt16[ElementCount]; + private static UInt16[] _data2 = new UInt16[ElementCount]; + + private static Vector128<UInt16> _clsVar1; + private static Vector128<UInt16> _clsVar2; + + private Vector128<UInt16> _fld1; + private Vector128<UInt16> _fld2; + + private SimpleBinaryOpTest__DataTable<UInt16> _dataTable; + + static SimpleBinaryOpTest__CompareEqualUInt16() + { + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (ushort)(random.Next(0, ushort.MaxValue)); _data2[i] = (ushort)(random.Next(0, ushort.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt16>, byte>(ref _clsVar1), ref Unsafe.As<UInt16, byte>(ref _data2[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt16>, byte>(ref _clsVar2), ref Unsafe.As<UInt16, byte>(ref _data1[0]), VectorSize); + } + + public SimpleBinaryOpTest__CompareEqualUInt16() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (ushort)(random.Next(0, ushort.MaxValue)); _data2[i] = (ushort)(random.Next(0, ushort.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt16>, byte>(ref _fld1), ref Unsafe.As<UInt16, byte>(ref _data1[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt16>, byte>(ref _fld2), ref Unsafe.As<UInt16, byte>(ref _data2[0]), VectorSize); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (ushort)(random.Next(0, ushort.MaxValue)); _data2[i] = (ushort)(random.Next(0, ushort.MaxValue)); } + _dataTable = new SimpleBinaryOpTest__DataTable<UInt16>(_data1, _data2, new UInt16[ElementCount], VectorSize); + } + + public bool IsSupported => Sse2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse2.CompareEqual( + Unsafe.Read<Vector128<UInt16>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<UInt16>>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse2.CompareEqual( + Sse2.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse2.CompareEqual( + Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.CompareEqual), new Type[] { typeof(Vector128<UInt16>), typeof(Vector128<UInt16>) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector128<UInt16>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<UInt16>>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<UInt16>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.CompareEqual), new Type[] { typeof(Vector128<UInt16>), typeof(Vector128<UInt16>) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<UInt16>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.CompareEqual), new Type[] { typeof(Vector128<UInt16>), typeof(Vector128<UInt16>) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<UInt16>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse2.CompareEqual( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read<Vector128<UInt16>>(_dataTable.inArray1Ptr); + var right = Unsafe.Read<Vector128<UInt16>>(_dataTable.inArray2Ptr); + var result = Sse2.CompareEqual(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)); + var result = Sse2.CompareEqual(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArray2Ptr)); + var result = Sse2.CompareEqual(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__CompareEqualUInt16(); + var result = Sse2.CompareEqual(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse2.CompareEqual(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128<UInt16> left, Vector128<UInt16> right, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[ElementCount]; + UInt16[] inArray2 = new UInt16[ElementCount]; + UInt16[] outArray = new UInt16[ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt16, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[ElementCount]; + UInt16[] inArray2 = new UInt16[ElementCount]; + UInt16[] outArray = new UInt16[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt16, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt16, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt16, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt16[] left, UInt16[] right, UInt16[] result, [CallerMemberName] string method = "") + { + if (result[0] != ((left[0] == right[0]) ? unchecked((ushort)(-1)) : 0)) + { + Succeeded = false; + } + else + { + for (var i = 1; i < left.Length; i++) + { + if (result[i] != ((left[i] == right[i]) ? unchecked((ushort)(-1)) : 0)) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Sse2)}.{nameof(Sse2.CompareEqual)}<UInt16>: {method} failed:"); + Console.WriteLine($" left: ({string.Join(", ", left)})"); + Console.WriteLine($" right: ({string.Join(", ", right)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareEqual.UInt32.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareEqual.UInt32.cs new file mode 100644 index 0000000000..e9c2db3767 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareEqual.UInt32.cs @@ -0,0 +1,315 @@ +// 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 CompareEqualUInt32() + { + var test = new SimpleBinaryOpTest__CompareEqualUInt32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + // 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(); + + // 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(); + + // 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 works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + 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__CompareEqualUInt32 + { + private const int VectorSize = 16; + private const int ElementCount = VectorSize / sizeof(UInt32); + + private static UInt32[] _data1 = new UInt32[ElementCount]; + private static UInt32[] _data2 = new UInt32[ElementCount]; + + private static Vector128<UInt32> _clsVar1; + private static Vector128<UInt32> _clsVar2; + + private Vector128<UInt32> _fld1; + private Vector128<UInt32> _fld2; + + private SimpleBinaryOpTest__DataTable<UInt32> _dataTable; + + static SimpleBinaryOpTest__CompareEqualUInt32() + { + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (uint)(random.Next(0, int.MaxValue)); _data2[i] = (uint)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt32>, byte>(ref _clsVar1), ref Unsafe.As<UInt32, byte>(ref _data2[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt32>, byte>(ref _clsVar2), ref Unsafe.As<UInt32, byte>(ref _data1[0]), VectorSize); + } + + public SimpleBinaryOpTest__CompareEqualUInt32() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (uint)(random.Next(0, int.MaxValue)); _data2[i] = (uint)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt32>, byte>(ref _fld1), ref Unsafe.As<UInt32, byte>(ref _data1[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt32>, byte>(ref _fld2), ref Unsafe.As<UInt32, byte>(ref _data2[0]), VectorSize); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (uint)(random.Next(0, int.MaxValue)); _data2[i] = (uint)(random.Next(0, int.MaxValue)); } + _dataTable = new SimpleBinaryOpTest__DataTable<UInt32>(_data1, _data2, new UInt32[ElementCount], VectorSize); + } + + public bool IsSupported => Sse2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse2.CompareEqual( + Unsafe.Read<Vector128<UInt32>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<UInt32>>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse2.CompareEqual( + Sse2.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse2.CompareEqual( + Sse2.LoadAlignedVector128((UInt32*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((UInt32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.CompareEqual), new Type[] { typeof(Vector128<UInt32>), typeof(Vector128<UInt32>) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector128<UInt32>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<UInt32>>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<UInt32>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.CompareEqual), new Type[] { typeof(Vector128<UInt32>), typeof(Vector128<UInt32>) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<UInt32>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.CompareEqual), new Type[] { typeof(Vector128<UInt32>), typeof(Vector128<UInt32>) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((UInt32*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((UInt32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<UInt32>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse2.CompareEqual( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read<Vector128<UInt32>>(_dataTable.inArray1Ptr); + var right = Unsafe.Read<Vector128<UInt32>>(_dataTable.inArray2Ptr); + var result = Sse2.CompareEqual(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)); + var result = Sse2.CompareEqual(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((UInt32*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((UInt32*)(_dataTable.inArray2Ptr)); + var result = Sse2.CompareEqual(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__CompareEqualUInt32(); + var result = Sse2.CompareEqual(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse2.CompareEqual(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128<UInt32> left, Vector128<UInt32> right, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[ElementCount]; + UInt32[] inArray2 = new UInt32[ElementCount]; + UInt32[] outArray = new UInt32[ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt32, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[ElementCount]; + UInt32[] inArray2 = new UInt32[ElementCount]; + UInt32[] outArray = new UInt32[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt32, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt32, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt32, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt32[] left, UInt32[] right, UInt32[] result, [CallerMemberName] string method = "") + { + if (result[0] != ((left[0] == right[0]) ? unchecked((uint)(-1)) : 0)) + { + Succeeded = false; + } + else + { + for (var i = 1; i < left.Length; i++) + { + if (result[i] != ((left[i] == right[i]) ? unchecked((uint)(-1)) : 0)) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Sse2)}.{nameof(Sse2.CompareEqual)}<UInt32>: {method} failed:"); + Console.WriteLine($" left: ({string.Join(", ", left)})"); + Console.WriteLine($" right: ({string.Join(", ", right)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareEqual.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareEqual.cs deleted file mode 100644 index 45ac941fe0..0000000000 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareEqual.cs +++ /dev/null @@ -1,150 +0,0 @@ -// 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. -// - -using System; -using System.Runtime.Intrinsics.X86; -using System.Runtime.Intrinsics; - -namespace IntelHardwareIntrinsicTest -{ - internal static partial class Program - { - const int Pass = 100; - const int Fail = 0; - - static unsafe int Main(string[] args) - { - int testResult = Pass; - int testsCount = 21; - string methodUnderTestName = nameof(Sse2.CompareEqual); - - if (Sse2.IsSupported) - { - using (var doubleTable = TestTableSse2<double>.Create(testsCount)) - using (var intTable = TestTableSse2<int>.Create(testsCount)) - using (var uintTable = TestTableSse2<uint>.Create(testsCount)) - using (var shortTable = TestTableSse2<short>.Create(testsCount)) - using (var ushortTable = TestTableSse2<ushort>.Create(testsCount)) - using (var sbyteTable = TestTableSse2<sbyte>.Create(testsCount)) - using (var byteTable = TestTableSse2<byte>.Create(testsCount)) - { - for (int i = 0; i < testsCount; i++) - { - (Vector128<double>, Vector128<double>, Vector128<double>) value = doubleTable[i]; - var result = Sse2.CompareEqual(value.Item1, value.Item2); - doubleTable.SetOutArray(result); - } - - for (int i = 0; i < testsCount; i++) - { - (Vector128<int>, Vector128<int>, Vector128<int>) value = intTable[i]; - var result = Sse2.CompareEqual(value.Item1, value.Item2); - intTable.SetOutArray(result); - } - - for (int i = 0; i < testsCount; i++) - { - (Vector128<uint>, Vector128<uint>, Vector128<uint>) value = uintTable[i]; - var result = Sse2.CompareEqual(value.Item1, value.Item2); - uintTable.SetOutArray(result); - } - - for (int i = 0; i < testsCount; i++) - { - (Vector128<short>, Vector128<short>, Vector128<short>) value = shortTable[i]; - var result = Sse2.CompareEqual(value.Item1, value.Item2); - shortTable.SetOutArray(result); - } - - for (int i = 0; i < testsCount; i++) - { - (Vector128<ushort>, Vector128<ushort>, Vector128<ushort>) value = ushortTable[i]; - var result = Sse2.CompareEqual(value.Item1, value.Item2); - ushortTable.SetOutArray(result); - } - - for (int i = 0; i < testsCount; i++) - { - (Vector128<sbyte>, Vector128<sbyte>, Vector128<sbyte>) value = sbyteTable[i]; - var result = Sse2.CompareEqual(value.Item1, value.Item2); - sbyteTable.SetOutArray(result); - } - - for (int i = 0; i < testsCount; i++) - { - (Vector128<byte>, Vector128<byte>, Vector128<byte>) value = byteTable[i]; - var result = Sse2.CompareEqual(value.Item1, value.Item2); - byteTable.SetOutArray(result); - } - - CheckMethod<double> checkDouble = (double x, double y, double z, ref double a) => - { - a = x == y ? BitConverter.Int64BitsToDouble(-1) : 0; - return BitConverter.DoubleToInt64Bits(a) == BitConverter.DoubleToInt64Bits(z); - }; - - if (!doubleTable.CheckResult(checkDouble)) - { - PrintError(doubleTable, methodUnderTestName, "(double x, double y, double z, ref double a) => (a = x == y ? -1l : 0) == z", checkDouble); - testResult = Fail; - } - - CheckMethod<int> checkInt32 = (int x, int y, int z, ref int a) => (a = x == y ? -1 : 0) == z; - - if (!intTable.CheckResult(checkInt32)) - { - PrintError(intTable, methodUnderTestName, "(int x, int y, int z, ref int a) => (a = x == y ? -1 : 0) == z);", checkInt32); - testResult = Fail; - } - - CheckMethod<uint> checkUInt32 = (uint x, uint y, uint z, ref uint a) => (a = x == y ? 0xffffffff : 0) == z; - - if (!uintTable.CheckResult(checkUInt32)) - { - PrintError(uintTable, methodUnderTestName, "(uint x, uint y, uint z, ref uint a) => (a = x == y ? 0xffffffff : 0) == z", checkUInt32); - testResult = Fail; - } - - CheckMethod<short> checkInt16 = (short x, short y, short z, ref short a) => (a = (short)(x == y ? -1 : 0)) == z; - - if (!shortTable.CheckResult(checkInt16)) - { - PrintError(shortTable, methodUnderTestName, "(short x, short y, short z, ref short a) => (a = (short)(x == y ? -1 : 0)) == z", checkInt16); - testResult = Fail; - } - - CheckMethod<ushort> checkUInt16 = (ushort x, ushort y, ushort z, ref ushort a) => (a = (ushort)(x == y ? 0xffff : 0)) == z; - - if (!ushortTable.CheckResult(checkUInt16)) - { - PrintError(ushortTable, methodUnderTestName, "(ushort x, ushort y, ushort z, ref ushort a) => (a = (ushort)(x == y ? 0xffff : 0)) == z", checkUInt16); - testResult = Fail; - } - - CheckMethod<sbyte> checkSByte = (sbyte x, sbyte y, sbyte z, ref sbyte a) => (a = (sbyte) (x == y ? -1 : 0)) == z; - - if (!sbyteTable.CheckResult(checkSByte)) - { - PrintError(sbyteTable, methodUnderTestName, "(sbyte x, sbyte y, sbyte z, ref sbyte a) => (a = (sbyte) (x == y ? -1 : 0) == z", checkSByte); - testResult = Fail; - } - - CheckMethod<byte> checkByte = (byte x, byte y, byte z, ref byte a) => (a = (byte)(x == y ? 0xff : 0)) == z; - - if (!byteTable.CheckResult(checkByte)) - { - PrintError(byteTable, methodUnderTestName, "(byte x, byte y, byte z, ref byte a) => (a = (byte)(x == y ? 0xff : 0)) == z", checkByte); - testResult = Fail; - } - } - } - else - { - Console.WriteLine($"Sse2.IsSupported: {Sse2.IsSupported}, skipped tests of {typeof(Sse2)}.{methodUnderTestName}"); - } - return testResult; - } - } -} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareEqual_r.csproj b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareEqual_r.csproj deleted file mode 100644 index 8cde1ea422..0000000000 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareEqual_r.csproj +++ /dev/null @@ -1,38 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" /> - <PropertyGroup> - <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> - <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> - <SchemaVersion>2.0</SchemaVersion> - <ProjectGuid>{EB82DD03-0CB7-41E2-8879-63C128833B6E}</ProjectGuid> - <OutputType>Exe</OutputType> - <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> - <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir> - <AllowUnsafeBlocks>true</AllowUnsafeBlocks> - </PropertyGroup> - <!-- Default configurations to help VS understand the configurations --> - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> - </PropertyGroup> - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' " /> - <ItemGroup> - <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies"> - <Visible>False</Visible> - </CodeAnalysisDependentAssemblyPaths> - </ItemGroup> - <PropertyGroup> - <DebugType>None</DebugType> - <Optimize> - </Optimize> - </PropertyGroup> - <ItemGroup> - <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" /> - </ItemGroup> - <ItemGroup> - <Compile Include="CompareEqual.cs" /> - <Compile Include="TestTableSse2.cs" /> - </ItemGroup> - <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" /> - <PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' "> - </PropertyGroup> -</Project>
\ No newline at end of file diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareEqual_ro.csproj b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareEqual_ro.csproj deleted file mode 100644 index 6b4082ff8e..0000000000 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareEqual_ro.csproj +++ /dev/null @@ -1,37 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" /> - <PropertyGroup> - <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> - <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> - <SchemaVersion>2.0</SchemaVersion> - <ProjectGuid>{81E414C4-4281-4C1F-BC30-EACDCD551D1D}</ProjectGuid> - <OutputType>Exe</OutputType> - <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> - <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir> - <AllowUnsafeBlocks>true</AllowUnsafeBlocks> - </PropertyGroup> - <!-- Default configurations to help VS understand the configurations --> - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> - </PropertyGroup> - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' " /> - <ItemGroup> - <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies"> - <Visible>False</Visible> - </CodeAnalysisDependentAssemblyPaths> - </ItemGroup> - <PropertyGroup> - <DebugType>None</DebugType> - <Optimize>True</Optimize> - </PropertyGroup> - <ItemGroup> - <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" /> - </ItemGroup> - <ItemGroup> - <Compile Include="CompareEqual.cs" /> - <Compile Include="TestTableSse2.cs" /> - </ItemGroup> - <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" /> - <PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' "> - </PropertyGroup> -</Project>
\ No newline at end of file diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareGreaterThan.Double.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareGreaterThan.Double.cs new file mode 100644 index 0000000000..bdc6052cf4 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareGreaterThan.Double.cs @@ -0,0 +1,315 @@ +// 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 CompareGreaterThanDouble() + { + var test = new SimpleBinaryOpTest__CompareGreaterThanDouble(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + // 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(); + + // 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(); + + // 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 works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + 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__CompareGreaterThanDouble + { + private const int VectorSize = 16; + private const int ElementCount = VectorSize / sizeof(Double); + + private static Double[] _data1 = new Double[ElementCount]; + private static Double[] _data2 = new Double[ElementCount]; + + private static Vector128<Double> _clsVar1; + private static Vector128<Double> _clsVar2; + + private Vector128<Double> _fld1; + private Vector128<Double> _fld2; + + private SimpleBinaryOpTest__DataTable<Double> _dataTable; + + static SimpleBinaryOpTest__CompareGreaterThanDouble() + { + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (double)(random.NextDouble()); _data2[i] = (double)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Double>, byte>(ref _clsVar1), ref Unsafe.As<Double, byte>(ref _data2[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Double>, byte>(ref _clsVar2), ref Unsafe.As<Double, byte>(ref _data1[0]), VectorSize); + } + + public SimpleBinaryOpTest__CompareGreaterThanDouble() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (double)(random.NextDouble()); _data2[i] = (double)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Double>, byte>(ref _fld1), ref Unsafe.As<Double, byte>(ref _data1[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Double>, byte>(ref _fld2), ref Unsafe.As<Double, byte>(ref _data2[0]), VectorSize); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (double)(random.NextDouble()); _data2[i] = (double)(random.NextDouble()); } + _dataTable = new SimpleBinaryOpTest__DataTable<Double>(_data1, _data2, new Double[ElementCount], VectorSize); + } + + public bool IsSupported => Sse2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse2.CompareGreaterThan( + Unsafe.Read<Vector128<Double>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<Double>>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse2.CompareGreaterThan( + Sse2.LoadVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Double*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse2.CompareGreaterThan( + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.CompareGreaterThan), new Type[] { typeof(Vector128<Double>), typeof(Vector128<Double>) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector128<Double>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<Double>>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Double>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.CompareGreaterThan), new Type[] { typeof(Vector128<Double>), typeof(Vector128<Double>) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Double*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Double>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.CompareGreaterThan), new Type[] { typeof(Vector128<Double>), typeof(Vector128<Double>) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Double>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse2.CompareGreaterThan( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read<Vector128<Double>>(_dataTable.inArray1Ptr); + var right = Unsafe.Read<Vector128<Double>>(_dataTable.inArray2Ptr); + var result = Sse2.CompareGreaterThan(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((Double*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((Double*)(_dataTable.inArray2Ptr)); + var result = Sse2.CompareGreaterThan(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray2Ptr)); + var result = Sse2.CompareGreaterThan(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__CompareGreaterThanDouble(); + var result = Sse2.CompareGreaterThan(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse2.CompareGreaterThan(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128<Double> left, Vector128<Double> right, void* result, [CallerMemberName] string method = "") + { + Double[] inArray1 = new Double[ElementCount]; + Double[] inArray2 = new Double[ElementCount]; + Double[] outArray = new Double[ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Double[] inArray1 = new Double[ElementCount]; + Double[] inArray2 = new Double[ElementCount]; + Double[] outArray = new Double[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Double[] left, Double[] right, Double[] result, [CallerMemberName] string method = "") + { + if (BitConverter.DoubleToInt64Bits(result[0]) != ((left[0] > right[0]) ? -1 : 0)) + { + Succeeded = false; + } + else + { + for (var i = 1; i < left.Length; i++) + { + if (BitConverter.DoubleToInt64Bits(result[i]) != ((left[i] > right[i]) ? -1 : 0)) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Sse2)}.{nameof(Sse2.CompareGreaterThan)}<Double>: {method} failed:"); + Console.WriteLine($" left: ({string.Join(", ", left)})"); + Console.WriteLine($" right: ({string.Join(", ", right)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareGreaterThan.Int16.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareGreaterThan.Int16.cs new file mode 100644 index 0000000000..4f5f5e6292 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareGreaterThan.Int16.cs @@ -0,0 +1,315 @@ +// 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 CompareGreaterThanInt16() + { + var test = new SimpleBinaryOpTest__CompareGreaterThanInt16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + // 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(); + + // 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(); + + // 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 works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + 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__CompareGreaterThanInt16 + { + private const int VectorSize = 16; + private const int ElementCount = VectorSize / sizeof(Int16); + + private static Int16[] _data1 = new Int16[ElementCount]; + private static Int16[] _data2 = new Int16[ElementCount]; + + private static Vector128<Int16> _clsVar1; + private static Vector128<Int16> _clsVar2; + + private Vector128<Int16> _fld1; + private Vector128<Int16> _fld2; + + private SimpleBinaryOpTest__DataTable<Int16> _dataTable; + + static SimpleBinaryOpTest__CompareGreaterThanInt16() + { + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (short)(random.Next(short.MinValue, short.MaxValue)); _data2[i] = (short)(random.Next(short.MinValue, short.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int16>, byte>(ref _clsVar1), ref Unsafe.As<Int16, byte>(ref _data2[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int16>, byte>(ref _clsVar2), ref Unsafe.As<Int16, byte>(ref _data1[0]), VectorSize); + } + + public SimpleBinaryOpTest__CompareGreaterThanInt16() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (short)(random.Next(short.MinValue, short.MaxValue)); _data2[i] = (short)(random.Next(short.MinValue, short.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int16>, byte>(ref _fld1), ref Unsafe.As<Int16, byte>(ref _data1[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int16>, byte>(ref _fld2), ref Unsafe.As<Int16, byte>(ref _data2[0]), VectorSize); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (short)(random.Next(short.MinValue, short.MaxValue)); _data2[i] = (short)(random.Next(short.MinValue, short.MaxValue)); } + _dataTable = new SimpleBinaryOpTest__DataTable<Int16>(_data1, _data2, new Int16[ElementCount], VectorSize); + } + + public bool IsSupported => Sse2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse2.CompareGreaterThan( + Unsafe.Read<Vector128<Int16>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<Int16>>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse2.CompareGreaterThan( + Sse2.LoadVector128((Int16*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Int16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse2.CompareGreaterThan( + Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.CompareGreaterThan), new Type[] { typeof(Vector128<Int16>), typeof(Vector128<Int16>) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector128<Int16>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<Int16>>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Int16>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.CompareGreaterThan), new Type[] { typeof(Vector128<Int16>), typeof(Vector128<Int16>) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Int16*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Int16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Int16>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.CompareGreaterThan), new Type[] { typeof(Vector128<Int16>), typeof(Vector128<Int16>) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Int16>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse2.CompareGreaterThan( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read<Vector128<Int16>>(_dataTable.inArray1Ptr); + var right = Unsafe.Read<Vector128<Int16>>(_dataTable.inArray2Ptr); + var result = Sse2.CompareGreaterThan(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((Int16*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((Int16*)(_dataTable.inArray2Ptr)); + var result = Sse2.CompareGreaterThan(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray2Ptr)); + var result = Sse2.CompareGreaterThan(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__CompareGreaterThanInt16(); + var result = Sse2.CompareGreaterThan(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse2.CompareGreaterThan(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128<Int16> left, Vector128<Int16> right, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[ElementCount]; + Int16[] inArray2 = new Int16[ElementCount]; + Int16[] outArray = new Int16[ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int16, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[ElementCount]; + Int16[] inArray2 = new Int16[ElementCount]; + Int16[] outArray = new Int16[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int16, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int16, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int16, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int16[] left, Int16[] right, Int16[] result, [CallerMemberName] string method = "") + { + if (result[0] != ((left[0] > right[0]) ? unchecked((short)(-1)) : 0)) + { + Succeeded = false; + } + else + { + for (var i = 1; i < left.Length; i++) + { + if (result[i] != ((left[i] > right[i]) ? unchecked((short)(-1)) : 0)) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Sse2)}.{nameof(Sse2.CompareGreaterThan)}<Int16>: {method} failed:"); + Console.WriteLine($" left: ({string.Join(", ", left)})"); + Console.WriteLine($" right: ({string.Join(", ", right)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareGreaterThan.Int32.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareGreaterThan.Int32.cs new file mode 100644 index 0000000000..e6c2541e4b --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareGreaterThan.Int32.cs @@ -0,0 +1,315 @@ +// 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 CompareGreaterThanInt32() + { + var test = new SimpleBinaryOpTest__CompareGreaterThanInt32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + // 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(); + + // 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(); + + // 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 works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + 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__CompareGreaterThanInt32 + { + private const int VectorSize = 16; + private const int ElementCount = VectorSize / sizeof(Int32); + + private static Int32[] _data1 = new Int32[ElementCount]; + private static Int32[] _data2 = new Int32[ElementCount]; + + private static Vector128<Int32> _clsVar1; + private static Vector128<Int32> _clsVar2; + + private Vector128<Int32> _fld1; + private Vector128<Int32> _fld2; + + private SimpleBinaryOpTest__DataTable<Int32> _dataTable; + + static SimpleBinaryOpTest__CompareGreaterThanInt32() + { + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (int)(random.Next(int.MinValue, int.MaxValue)); _data2[i] = (int)(random.Next(int.MinValue, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int32>, byte>(ref _clsVar1), ref Unsafe.As<Int32, byte>(ref _data2[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int32>, byte>(ref _clsVar2), ref Unsafe.As<Int32, byte>(ref _data1[0]), VectorSize); + } + + public SimpleBinaryOpTest__CompareGreaterThanInt32() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (int)(random.Next(int.MinValue, int.MaxValue)); _data2[i] = (int)(random.Next(int.MinValue, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int32>, byte>(ref _fld1), ref Unsafe.As<Int32, byte>(ref _data1[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int32>, byte>(ref _fld2), ref Unsafe.As<Int32, byte>(ref _data2[0]), VectorSize); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (int)(random.Next(int.MinValue, int.MaxValue)); _data2[i] = (int)(random.Next(int.MinValue, int.MaxValue)); } + _dataTable = new SimpleBinaryOpTest__DataTable<Int32>(_data1, _data2, new Int32[ElementCount], VectorSize); + } + + public bool IsSupported => Sse2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse2.CompareGreaterThan( + Unsafe.Read<Vector128<Int32>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<Int32>>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse2.CompareGreaterThan( + Sse2.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Int32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse2.CompareGreaterThan( + Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.CompareGreaterThan), new Type[] { typeof(Vector128<Int32>), typeof(Vector128<Int32>) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector128<Int32>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<Int32>>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Int32>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.CompareGreaterThan), new Type[] { typeof(Vector128<Int32>), typeof(Vector128<Int32>) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Int32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Int32>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.CompareGreaterThan), new Type[] { typeof(Vector128<Int32>), typeof(Vector128<Int32>) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Int32>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse2.CompareGreaterThan( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read<Vector128<Int32>>(_dataTable.inArray1Ptr); + var right = Unsafe.Read<Vector128<Int32>>(_dataTable.inArray2Ptr); + var result = Sse2.CompareGreaterThan(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((Int32*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((Int32*)(_dataTable.inArray2Ptr)); + var result = Sse2.CompareGreaterThan(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray2Ptr)); + var result = Sse2.CompareGreaterThan(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__CompareGreaterThanInt32(); + var result = Sse2.CompareGreaterThan(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse2.CompareGreaterThan(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128<Int32> left, Vector128<Int32> right, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[ElementCount]; + Int32[] inArray2 = new Int32[ElementCount]; + Int32[] outArray = new Int32[ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int32, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[ElementCount]; + Int32[] inArray2 = new Int32[ElementCount]; + Int32[] outArray = new Int32[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int32, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int32, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int32, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int32[] left, Int32[] right, Int32[] result, [CallerMemberName] string method = "") + { + if (result[0] != ((left[0] > right[0]) ? unchecked((int)(-1)) : 0)) + { + Succeeded = false; + } + else + { + for (var i = 1; i < left.Length; i++) + { + if (result[i] != ((left[i] > right[i]) ? unchecked((int)(-1)) : 0)) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Sse2)}.{nameof(Sse2.CompareGreaterThan)}<Int32>: {method} failed:"); + Console.WriteLine($" left: ({string.Join(", ", left)})"); + Console.WriteLine($" right: ({string.Join(", ", right)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareGreaterThan.SByte.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareGreaterThan.SByte.cs new file mode 100644 index 0000000000..56f523f98b --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareGreaterThan.SByte.cs @@ -0,0 +1,315 @@ +// 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 CompareGreaterThanSByte() + { + var test = new SimpleBinaryOpTest__CompareGreaterThanSByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + // 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(); + + // 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(); + + // 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 works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + 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__CompareGreaterThanSByte + { + private const int VectorSize = 16; + private const int ElementCount = VectorSize / sizeof(SByte); + + private static SByte[] _data1 = new SByte[ElementCount]; + private static SByte[] _data2 = new SByte[ElementCount]; + + private static Vector128<SByte> _clsVar1; + private static Vector128<SByte> _clsVar2; + + private Vector128<SByte> _fld1; + private Vector128<SByte> _fld2; + + private SimpleBinaryOpTest__DataTable<SByte> _dataTable; + + static SimpleBinaryOpTest__CompareGreaterThanSByte() + { + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue)); _data2[i] = (sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<SByte>, byte>(ref _clsVar1), ref Unsafe.As<SByte, byte>(ref _data2[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<SByte>, byte>(ref _clsVar2), ref Unsafe.As<SByte, byte>(ref _data1[0]), VectorSize); + } + + public SimpleBinaryOpTest__CompareGreaterThanSByte() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue)); _data2[i] = (sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<SByte>, byte>(ref _fld1), ref Unsafe.As<SByte, byte>(ref _data1[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<SByte>, byte>(ref _fld2), ref Unsafe.As<SByte, byte>(ref _data2[0]), VectorSize); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue)); _data2[i] = (sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue)); } + _dataTable = new SimpleBinaryOpTest__DataTable<SByte>(_data1, _data2, new SByte[ElementCount], VectorSize); + } + + public bool IsSupported => Sse2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse2.CompareGreaterThan( + Unsafe.Read<Vector128<SByte>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<SByte>>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse2.CompareGreaterThan( + Sse2.LoadVector128((SByte*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((SByte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse2.CompareGreaterThan( + Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.CompareGreaterThan), new Type[] { typeof(Vector128<SByte>), typeof(Vector128<SByte>) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector128<SByte>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<SByte>>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<SByte>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.CompareGreaterThan), new Type[] { typeof(Vector128<SByte>), typeof(Vector128<SByte>) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((SByte*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((SByte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<SByte>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.CompareGreaterThan), new Type[] { typeof(Vector128<SByte>), typeof(Vector128<SByte>) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<SByte>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse2.CompareGreaterThan( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read<Vector128<SByte>>(_dataTable.inArray1Ptr); + var right = Unsafe.Read<Vector128<SByte>>(_dataTable.inArray2Ptr); + var result = Sse2.CompareGreaterThan(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((SByte*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((SByte*)(_dataTable.inArray2Ptr)); + var result = Sse2.CompareGreaterThan(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArray2Ptr)); + var result = Sse2.CompareGreaterThan(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__CompareGreaterThanSByte(); + var result = Sse2.CompareGreaterThan(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse2.CompareGreaterThan(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128<SByte> left, Vector128<SByte> right, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[ElementCount]; + SByte[] inArray2 = new SByte[ElementCount]; + SByte[] outArray = new SByte[ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<SByte, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[ElementCount]; + SByte[] inArray2 = new SByte[ElementCount]; + SByte[] outArray = new SByte[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<SByte, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<SByte, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<SByte, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(SByte[] left, SByte[] right, SByte[] result, [CallerMemberName] string method = "") + { + if (result[0] != ((left[0] > right[0]) ? unchecked((sbyte)(-1)) : 0)) + { + Succeeded = false; + } + else + { + for (var i = 1; i < left.Length; i++) + { + if (result[i] != ((left[i] > right[i]) ? unchecked((sbyte)(-1)) : 0)) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Sse2)}.{nameof(Sse2.CompareGreaterThan)}<SByte>: {method} failed:"); + Console.WriteLine($" left: ({string.Join(", ", left)})"); + Console.WriteLine($" right: ({string.Join(", ", right)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareGreaterThan.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareGreaterThan.cs deleted file mode 100644 index 04290ac010..0000000000 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareGreaterThan.cs +++ /dev/null @@ -1,105 +0,0 @@ -// 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. -// - -using System; -using System.Runtime.Intrinsics; -using System.Runtime.Intrinsics.X86; - -namespace IntelHardwareIntrinsicTest -{ - internal static partial class Program - { - private const int Pass = 100; - private const int Fail = 0; - - static unsafe int Main(string[] args) - { - int testResult = Pass; - int testsCount = 21; - string methodUnderTestName = nameof(Sse2.CompareGreaterThan); - - if (Sse2.IsSupported) - { - using (var doubleTable = TestTableSse2<double>.Create(testsCount)) - using (var intTable = TestTableSse2<int>.Create(testsCount)) - using (var shortTable = TestTableSse2<short>.Create(testsCount)) - using (var sbyteTable = TestTableSse2<sbyte>.Create(testsCount)) - { - for (int i = 0; i < testsCount; i++) - { - (Vector128<double>, Vector128<double>, Vector128<double>) value = doubleTable[i]; - var result = Sse2.CompareGreaterThan(value.Item1, value.Item2); - doubleTable.SetOutArray(result); - } - - for (int i = 0; i < testsCount; i++) - { - (Vector128<int>, Vector128<int>, Vector128<int>) value = intTable[i]; - var result = Sse2.CompareGreaterThan(value.Item1, value.Item2); - intTable.SetOutArray(result); - } - - for (int i = 0; i < testsCount; i++) - { - (Vector128<short>, Vector128<short>, Vector128<short>) value = shortTable[i]; - var result = Sse2.CompareGreaterThan(value.Item1, value.Item2); - shortTable.SetOutArray(result); - } - - for (int i = 0; i < testsCount; i++) - { - (Vector128<sbyte>, Vector128<sbyte>, Vector128<sbyte>) value = sbyteTable[i]; - var result = Sse2.CompareGreaterThan(value.Item1, value.Item2); - sbyteTable.SetOutArray(result); - } - - CheckMethod<double> checkDouble = (double x, double y, double z, ref double a) => - { - a = x > y ? BitConverter.Int64BitsToDouble(-1) : 0; - return BitConverter.DoubleToInt64Bits(a) == BitConverter.DoubleToInt64Bits(z); - }; - - if (!doubleTable.CheckResult(checkDouble)) - { - PrintError(doubleTable, methodUnderTestName, "(x, y, z, ref a) => (a = x > y ? double.NaN : 0) == z", checkDouble); - testResult = Fail; - } - - CheckMethod<int> checkInt32 = (int x, int y, int z, ref int a) => (a = x > y ? -1 : 0) == z; - - if (!intTable.CheckResult(checkInt32)) - { - PrintError(intTable, methodUnderTestName, "(x, y, z, a) => (a = x > y ? -1 : 0) == z", checkInt32); - testResult = Fail; - } - - CheckMethod<short> checkInt16 = (short x, short y, short z, ref short a) - => (a = (short)(x > y ? -1 : 0)) == z; - - if (!shortTable.CheckResult(checkInt16)) - { - PrintError(shortTable, methodUnderTestName, "(x, y, z) => (x > y ? -1 : 0) == z", checkInt16); - testResult = Fail; - } - - CheckMethod<sbyte> checkSByte = (sbyte x, sbyte y, sbyte z, ref sbyte a) - => (a = (sbyte)(x > y ? -1 : 0)) == z; - - if (!sbyteTable.CheckResult(checkSByte)) - { - PrintError(sbyteTable, methodUnderTestName, "(x, y, z) => (x > y ? -1 : 0) == z", checkSByte); - testResult = Fail; - } - } - } - else - { - Console.WriteLine($"Sse2.IsSupported: {Sse2.IsSupported}, skipped tests of {typeof(Sse2)}.{methodUnderTestName}"); - } - - return testResult; - } - } -} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareGreaterThanOrEqual.Double.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareGreaterThanOrEqual.Double.cs new file mode 100644 index 0000000000..2af59f78d0 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareGreaterThanOrEqual.Double.cs @@ -0,0 +1,315 @@ +// 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 CompareGreaterThanOrEqualDouble() + { + var test = new SimpleBinaryOpTest__CompareGreaterThanOrEqualDouble(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + // 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(); + + // 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(); + + // 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 works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + 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__CompareGreaterThanOrEqualDouble + { + private const int VectorSize = 16; + private const int ElementCount = VectorSize / sizeof(Double); + + private static Double[] _data1 = new Double[ElementCount]; + private static Double[] _data2 = new Double[ElementCount]; + + private static Vector128<Double> _clsVar1; + private static Vector128<Double> _clsVar2; + + private Vector128<Double> _fld1; + private Vector128<Double> _fld2; + + private SimpleBinaryOpTest__DataTable<Double> _dataTable; + + static SimpleBinaryOpTest__CompareGreaterThanOrEqualDouble() + { + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (double)(random.NextDouble()); _data2[i] = (double)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Double>, byte>(ref _clsVar1), ref Unsafe.As<Double, byte>(ref _data2[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Double>, byte>(ref _clsVar2), ref Unsafe.As<Double, byte>(ref _data1[0]), VectorSize); + } + + public SimpleBinaryOpTest__CompareGreaterThanOrEqualDouble() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (double)(random.NextDouble()); _data2[i] = (double)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Double>, byte>(ref _fld1), ref Unsafe.As<Double, byte>(ref _data1[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Double>, byte>(ref _fld2), ref Unsafe.As<Double, byte>(ref _data2[0]), VectorSize); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (double)(random.NextDouble()); _data2[i] = (double)(random.NextDouble()); } + _dataTable = new SimpleBinaryOpTest__DataTable<Double>(_data1, _data2, new Double[ElementCount], VectorSize); + } + + public bool IsSupported => Sse2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse2.CompareGreaterThanOrEqual( + Unsafe.Read<Vector128<Double>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<Double>>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse2.CompareGreaterThanOrEqual( + Sse2.LoadVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Double*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse2.CompareGreaterThanOrEqual( + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.CompareGreaterThanOrEqual), new Type[] { typeof(Vector128<Double>), typeof(Vector128<Double>) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector128<Double>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<Double>>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Double>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.CompareGreaterThanOrEqual), new Type[] { typeof(Vector128<Double>), typeof(Vector128<Double>) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Double*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Double>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.CompareGreaterThanOrEqual), new Type[] { typeof(Vector128<Double>), typeof(Vector128<Double>) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Double>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse2.CompareGreaterThanOrEqual( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read<Vector128<Double>>(_dataTable.inArray1Ptr); + var right = Unsafe.Read<Vector128<Double>>(_dataTable.inArray2Ptr); + var result = Sse2.CompareGreaterThanOrEqual(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((Double*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((Double*)(_dataTable.inArray2Ptr)); + var result = Sse2.CompareGreaterThanOrEqual(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray2Ptr)); + var result = Sse2.CompareGreaterThanOrEqual(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__CompareGreaterThanOrEqualDouble(); + var result = Sse2.CompareGreaterThanOrEqual(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse2.CompareGreaterThanOrEqual(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128<Double> left, Vector128<Double> right, void* result, [CallerMemberName] string method = "") + { + Double[] inArray1 = new Double[ElementCount]; + Double[] inArray2 = new Double[ElementCount]; + Double[] outArray = new Double[ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Double[] inArray1 = new Double[ElementCount]; + Double[] inArray2 = new Double[ElementCount]; + Double[] outArray = new Double[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Double[] left, Double[] right, Double[] result, [CallerMemberName] string method = "") + { + if (BitConverter.DoubleToInt64Bits(result[0]) != ((left[0] >= right[0]) ? -1 : 0)) + { + Succeeded = false; + } + else + { + for (var i = 1; i < left.Length; i++) + { + if (BitConverter.DoubleToInt64Bits(result[i]) != ((left[i] >= right[i]) ? -1 : 0)) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Sse2)}.{nameof(Sse2.CompareGreaterThanOrEqual)}<Double>: {method} failed:"); + Console.WriteLine($" left: ({string.Join(", ", left)})"); + Console.WriteLine($" right: ({string.Join(", ", right)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareGreaterThanOrEqual.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareGreaterThanOrEqual.cs deleted file mode 100644 index 1555ff2b5f..0000000000 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareGreaterThanOrEqual.cs +++ /dev/null @@ -1,55 +0,0 @@ -// 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. -// - -using System; -using System.Runtime.Intrinsics; -using System.Runtime.Intrinsics.X86; - -namespace IntelHardwareIntrinsicTest -{ - internal static partial class Program - { - private const int Pass = 100; - private const int Fail = 0; - - static unsafe int Main(string[] args) - { - int testResult = Pass; - int testsCount = 21; - string methodUnderTestName = nameof(Sse2.CompareGreaterThanOrEqual); - - if (Sse2.IsSupported) - { - using (var doubleTable = TestTableSse2<double>.Create(testsCount)) - { - for (int i = 0; i < testsCount; i++) - { - (Vector128<double>, Vector128<double>, Vector128<double>) value = doubleTable[i]; - var result = Sse2.CompareGreaterThanOrEqual(value.Item1, value.Item2); - doubleTable.SetOutArray(result); - } - - CheckMethod<double> checkDouble = (double x, double y, double z, ref double a) => - { - a = x >= y ? BitConverter.Int64BitsToDouble(-1) : 0; - return BitConverter.DoubleToInt64Bits(a) == BitConverter.DoubleToInt64Bits(z); - }; - - if (!doubleTable.CheckResult(checkDouble)) - { - PrintError(doubleTable, methodUnderTestName, "(x, y, z, ref a) => (a = x > y ? double.NaN : 0) == z", checkDouble); - testResult = Fail; - } - } - } - else - { - Console.WriteLine($"Sse2.IsSupported: {Sse2.IsSupported}, skipped tests of {typeof(Sse2)}.{methodUnderTestName}"); - } - - return testResult; - } - } -} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareGreaterThanOrEqual_r.csproj b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareGreaterThanOrEqual_r.csproj deleted file mode 100644 index 725f16813e..0000000000 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareGreaterThanOrEqual_r.csproj +++ /dev/null @@ -1,38 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" /> - <PropertyGroup> - <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> - <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> - <SchemaVersion>2.0</SchemaVersion> - <ProjectGuid>{87F2B90D-85D3-4304-99D3-355F109BE961}</ProjectGuid> - <OutputType>Exe</OutputType> - <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> - <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir> - <AllowUnsafeBlocks>true</AllowUnsafeBlocks> - </PropertyGroup> - <!-- Default configurations to help VS understand the configurations --> - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> - </PropertyGroup> - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' " /> - <ItemGroup> - <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies"> - <Visible>False</Visible> - </CodeAnalysisDependentAssemblyPaths> - </ItemGroup> - <PropertyGroup> - <DebugType>None</DebugType> - <Optimize> - </Optimize> - </PropertyGroup> - <ItemGroup> - <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" /> - </ItemGroup> - <ItemGroup> - <Compile Include="CompareGreaterThanOrEqual.cs" /> - <Compile Include="TestTableSse2.cs" /> - </ItemGroup> - <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" /> - <PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' "> - </PropertyGroup> -</Project>
\ No newline at end of file diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareGreaterThanOrEqual_ro.csproj b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareGreaterThanOrEqual_ro.csproj deleted file mode 100644 index 08c738606d..0000000000 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareGreaterThanOrEqual_ro.csproj +++ /dev/null @@ -1,37 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" /> - <PropertyGroup> - <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> - <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> - <SchemaVersion>2.0</SchemaVersion> - <ProjectGuid>{A9EBC815-0839-4047-8602-7AB7AFB9C876}</ProjectGuid> - <OutputType>Exe</OutputType> - <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> - <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir> - <AllowUnsafeBlocks>true</AllowUnsafeBlocks> - </PropertyGroup> - <!-- Default configurations to help VS understand the configurations --> - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> - </PropertyGroup> - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' " /> - <ItemGroup> - <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies"> - <Visible>False</Visible> - </CodeAnalysisDependentAssemblyPaths> - </ItemGroup> - <PropertyGroup> - <DebugType>None</DebugType> - <Optimize>True</Optimize> - </PropertyGroup> - <ItemGroup> - <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" /> - </ItemGroup> - <ItemGroup> - <Compile Include="CompareGreaterThanOrEqual.cs" /> - <Compile Include="TestTableSse2.cs" /> - </ItemGroup> - <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" /> - <PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' "> - </PropertyGroup> -</Project>
\ No newline at end of file diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareGreaterThan_r.csproj b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareGreaterThan_r.csproj deleted file mode 100644 index f93b43835c..0000000000 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareGreaterThan_r.csproj +++ /dev/null @@ -1,38 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" /> - <PropertyGroup> - <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> - <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> - <SchemaVersion>2.0</SchemaVersion> - <ProjectGuid>{C28A4AAF-7F4E-4FC2-B7E8-AB856A453C8F}</ProjectGuid> - <OutputType>Exe</OutputType> - <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> - <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir> - <AllowUnsafeBlocks>true</AllowUnsafeBlocks> - </PropertyGroup> - <!-- Default configurations to help VS understand the configurations --> - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> - </PropertyGroup> - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' " /> - <ItemGroup> - <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies"> - <Visible>False</Visible> - </CodeAnalysisDependentAssemblyPaths> - </ItemGroup> - <PropertyGroup> - <DebugType>None</DebugType> - <Optimize> - </Optimize> - </PropertyGroup> - <ItemGroup> - <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" /> - </ItemGroup> - <ItemGroup> - <Compile Include="CompareGreaterThan.cs" /> - <Compile Include="TestTableSse2.cs" /> - </ItemGroup> - <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" /> - <PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' "> - </PropertyGroup> -</Project>
\ No newline at end of file diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareGreaterThan_ro.csproj b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareGreaterThan_ro.csproj deleted file mode 100644 index b07cf68973..0000000000 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareGreaterThan_ro.csproj +++ /dev/null @@ -1,37 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" /> - <PropertyGroup> - <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> - <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> - <SchemaVersion>2.0</SchemaVersion> - <ProjectGuid>{083F679A-B810-4523-892B-B86CC2089A05}</ProjectGuid> - <OutputType>Exe</OutputType> - <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> - <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir> - <AllowUnsafeBlocks>true</AllowUnsafeBlocks> - </PropertyGroup> - <!-- Default configurations to help VS understand the configurations --> - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> - </PropertyGroup> - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' " /> - <ItemGroup> - <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies"> - <Visible>False</Visible> - </CodeAnalysisDependentAssemblyPaths> - </ItemGroup> - <PropertyGroup> - <DebugType>None</DebugType> - <Optimize>True</Optimize> - </PropertyGroup> - <ItemGroup> - <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" /> - </ItemGroup> - <ItemGroup> - <Compile Include="CompareGreaterThan.cs" /> - <Compile Include="TestTableSse2.cs" /> - </ItemGroup> - <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" /> - <PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' "> - </PropertyGroup> -</Project>
\ No newline at end of file diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareLessThan.Double.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareLessThan.Double.cs new file mode 100644 index 0000000000..937d4d8576 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareLessThan.Double.cs @@ -0,0 +1,315 @@ +// 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 CompareLessThanDouble() + { + var test = new SimpleBinaryOpTest__CompareLessThanDouble(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + // 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(); + + // 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(); + + // 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 works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + 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__CompareLessThanDouble + { + private const int VectorSize = 16; + private const int ElementCount = VectorSize / sizeof(Double); + + private static Double[] _data1 = new Double[ElementCount]; + private static Double[] _data2 = new Double[ElementCount]; + + private static Vector128<Double> _clsVar1; + private static Vector128<Double> _clsVar2; + + private Vector128<Double> _fld1; + private Vector128<Double> _fld2; + + private SimpleBinaryOpTest__DataTable<Double> _dataTable; + + static SimpleBinaryOpTest__CompareLessThanDouble() + { + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (double)(random.NextDouble()); _data2[i] = (double)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Double>, byte>(ref _clsVar1), ref Unsafe.As<Double, byte>(ref _data2[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Double>, byte>(ref _clsVar2), ref Unsafe.As<Double, byte>(ref _data1[0]), VectorSize); + } + + public SimpleBinaryOpTest__CompareLessThanDouble() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (double)(random.NextDouble()); _data2[i] = (double)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Double>, byte>(ref _fld1), ref Unsafe.As<Double, byte>(ref _data1[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Double>, byte>(ref _fld2), ref Unsafe.As<Double, byte>(ref _data2[0]), VectorSize); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (double)(random.NextDouble()); _data2[i] = (double)(random.NextDouble()); } + _dataTable = new SimpleBinaryOpTest__DataTable<Double>(_data1, _data2, new Double[ElementCount], VectorSize); + } + + public bool IsSupported => Sse2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse2.CompareLessThan( + Unsafe.Read<Vector128<Double>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<Double>>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse2.CompareLessThan( + Sse2.LoadVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Double*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse2.CompareLessThan( + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.CompareLessThan), new Type[] { typeof(Vector128<Double>), typeof(Vector128<Double>) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector128<Double>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<Double>>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Double>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.CompareLessThan), new Type[] { typeof(Vector128<Double>), typeof(Vector128<Double>) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Double*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Double>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.CompareLessThan), new Type[] { typeof(Vector128<Double>), typeof(Vector128<Double>) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Double>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse2.CompareLessThan( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read<Vector128<Double>>(_dataTable.inArray1Ptr); + var right = Unsafe.Read<Vector128<Double>>(_dataTable.inArray2Ptr); + var result = Sse2.CompareLessThan(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((Double*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((Double*)(_dataTable.inArray2Ptr)); + var result = Sse2.CompareLessThan(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray2Ptr)); + var result = Sse2.CompareLessThan(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__CompareLessThanDouble(); + var result = Sse2.CompareLessThan(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse2.CompareLessThan(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128<Double> left, Vector128<Double> right, void* result, [CallerMemberName] string method = "") + { + Double[] inArray1 = new Double[ElementCount]; + Double[] inArray2 = new Double[ElementCount]; + Double[] outArray = new Double[ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Double[] inArray1 = new Double[ElementCount]; + Double[] inArray2 = new Double[ElementCount]; + Double[] outArray = new Double[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Double[] left, Double[] right, Double[] result, [CallerMemberName] string method = "") + { + if (BitConverter.DoubleToInt64Bits(result[0]) != ((left[0] < right[0]) ? -1 : 0)) + { + Succeeded = false; + } + else + { + for (var i = 1; i < left.Length; i++) + { + if (BitConverter.DoubleToInt64Bits(result[i]) != ((left[i] < right[i]) ? -1 : 0)) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Sse2)}.{nameof(Sse2.CompareLessThan)}<Double>: {method} failed:"); + Console.WriteLine($" left: ({string.Join(", ", left)})"); + Console.WriteLine($" right: ({string.Join(", ", right)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareLessThan.Int16.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareLessThan.Int16.cs new file mode 100644 index 0000000000..77bf3a4347 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareLessThan.Int16.cs @@ -0,0 +1,315 @@ +// 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 CompareLessThanInt16() + { + var test = new SimpleBinaryOpTest__CompareLessThanInt16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + // 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(); + + // 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(); + + // 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 works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + 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__CompareLessThanInt16 + { + private const int VectorSize = 16; + private const int ElementCount = VectorSize / sizeof(Int16); + + private static Int16[] _data1 = new Int16[ElementCount]; + private static Int16[] _data2 = new Int16[ElementCount]; + + private static Vector128<Int16> _clsVar1; + private static Vector128<Int16> _clsVar2; + + private Vector128<Int16> _fld1; + private Vector128<Int16> _fld2; + + private SimpleBinaryOpTest__DataTable<Int16> _dataTable; + + static SimpleBinaryOpTest__CompareLessThanInt16() + { + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (short)(random.Next(short.MinValue, short.MaxValue)); _data2[i] = (short)(random.Next(short.MinValue, short.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int16>, byte>(ref _clsVar1), ref Unsafe.As<Int16, byte>(ref _data2[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int16>, byte>(ref _clsVar2), ref Unsafe.As<Int16, byte>(ref _data1[0]), VectorSize); + } + + public SimpleBinaryOpTest__CompareLessThanInt16() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (short)(random.Next(short.MinValue, short.MaxValue)); _data2[i] = (short)(random.Next(short.MinValue, short.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int16>, byte>(ref _fld1), ref Unsafe.As<Int16, byte>(ref _data1[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int16>, byte>(ref _fld2), ref Unsafe.As<Int16, byte>(ref _data2[0]), VectorSize); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (short)(random.Next(short.MinValue, short.MaxValue)); _data2[i] = (short)(random.Next(short.MinValue, short.MaxValue)); } + _dataTable = new SimpleBinaryOpTest__DataTable<Int16>(_data1, _data2, new Int16[ElementCount], VectorSize); + } + + public bool IsSupported => Sse2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse2.CompareLessThan( + Unsafe.Read<Vector128<Int16>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<Int16>>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse2.CompareLessThan( + Sse2.LoadVector128((Int16*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Int16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse2.CompareLessThan( + Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.CompareLessThan), new Type[] { typeof(Vector128<Int16>), typeof(Vector128<Int16>) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector128<Int16>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<Int16>>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Int16>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.CompareLessThan), new Type[] { typeof(Vector128<Int16>), typeof(Vector128<Int16>) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Int16*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Int16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Int16>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.CompareLessThan), new Type[] { typeof(Vector128<Int16>), typeof(Vector128<Int16>) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Int16>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse2.CompareLessThan( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read<Vector128<Int16>>(_dataTable.inArray1Ptr); + var right = Unsafe.Read<Vector128<Int16>>(_dataTable.inArray2Ptr); + var result = Sse2.CompareLessThan(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((Int16*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((Int16*)(_dataTable.inArray2Ptr)); + var result = Sse2.CompareLessThan(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray2Ptr)); + var result = Sse2.CompareLessThan(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__CompareLessThanInt16(); + var result = Sse2.CompareLessThan(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse2.CompareLessThan(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128<Int16> left, Vector128<Int16> right, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[ElementCount]; + Int16[] inArray2 = new Int16[ElementCount]; + Int16[] outArray = new Int16[ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int16, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[ElementCount]; + Int16[] inArray2 = new Int16[ElementCount]; + Int16[] outArray = new Int16[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int16, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int16, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int16, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int16[] left, Int16[] right, Int16[] result, [CallerMemberName] string method = "") + { + if (result[0] != ((left[0] < right[0]) ? unchecked((short)(-1)) : 0)) + { + Succeeded = false; + } + else + { + for (var i = 1; i < left.Length; i++) + { + if (result[i] != ((left[i] < right[i]) ? unchecked((short)(-1)) : 0)) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Sse2)}.{nameof(Sse2.CompareLessThan)}<Int16>: {method} failed:"); + Console.WriteLine($" left: ({string.Join(", ", left)})"); + Console.WriteLine($" right: ({string.Join(", ", right)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareLessThan.Int32.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareLessThan.Int32.cs new file mode 100644 index 0000000000..29042f122f --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareLessThan.Int32.cs @@ -0,0 +1,315 @@ +// 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 CompareLessThanInt32() + { + var test = new SimpleBinaryOpTest__CompareLessThanInt32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + // 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(); + + // 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(); + + // 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 works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + 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__CompareLessThanInt32 + { + private const int VectorSize = 16; + private const int ElementCount = VectorSize / sizeof(Int32); + + private static Int32[] _data1 = new Int32[ElementCount]; + private static Int32[] _data2 = new Int32[ElementCount]; + + private static Vector128<Int32> _clsVar1; + private static Vector128<Int32> _clsVar2; + + private Vector128<Int32> _fld1; + private Vector128<Int32> _fld2; + + private SimpleBinaryOpTest__DataTable<Int32> _dataTable; + + static SimpleBinaryOpTest__CompareLessThanInt32() + { + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (int)(random.Next(int.MinValue, int.MaxValue)); _data2[i] = (int)(random.Next(int.MinValue, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int32>, byte>(ref _clsVar1), ref Unsafe.As<Int32, byte>(ref _data2[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int32>, byte>(ref _clsVar2), ref Unsafe.As<Int32, byte>(ref _data1[0]), VectorSize); + } + + public SimpleBinaryOpTest__CompareLessThanInt32() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (int)(random.Next(int.MinValue, int.MaxValue)); _data2[i] = (int)(random.Next(int.MinValue, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int32>, byte>(ref _fld1), ref Unsafe.As<Int32, byte>(ref _data1[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int32>, byte>(ref _fld2), ref Unsafe.As<Int32, byte>(ref _data2[0]), VectorSize); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (int)(random.Next(int.MinValue, int.MaxValue)); _data2[i] = (int)(random.Next(int.MinValue, int.MaxValue)); } + _dataTable = new SimpleBinaryOpTest__DataTable<Int32>(_data1, _data2, new Int32[ElementCount], VectorSize); + } + + public bool IsSupported => Sse2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse2.CompareLessThan( + Unsafe.Read<Vector128<Int32>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<Int32>>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse2.CompareLessThan( + Sse2.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Int32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse2.CompareLessThan( + Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.CompareLessThan), new Type[] { typeof(Vector128<Int32>), typeof(Vector128<Int32>) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector128<Int32>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<Int32>>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Int32>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.CompareLessThan), new Type[] { typeof(Vector128<Int32>), typeof(Vector128<Int32>) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Int32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Int32>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.CompareLessThan), new Type[] { typeof(Vector128<Int32>), typeof(Vector128<Int32>) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Int32>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse2.CompareLessThan( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read<Vector128<Int32>>(_dataTable.inArray1Ptr); + var right = Unsafe.Read<Vector128<Int32>>(_dataTable.inArray2Ptr); + var result = Sse2.CompareLessThan(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((Int32*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((Int32*)(_dataTable.inArray2Ptr)); + var result = Sse2.CompareLessThan(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray2Ptr)); + var result = Sse2.CompareLessThan(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__CompareLessThanInt32(); + var result = Sse2.CompareLessThan(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse2.CompareLessThan(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128<Int32> left, Vector128<Int32> right, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[ElementCount]; + Int32[] inArray2 = new Int32[ElementCount]; + Int32[] outArray = new Int32[ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int32, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[ElementCount]; + Int32[] inArray2 = new Int32[ElementCount]; + Int32[] outArray = new Int32[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int32, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int32, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int32, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int32[] left, Int32[] right, Int32[] result, [CallerMemberName] string method = "") + { + if (result[0] != ((left[0] < right[0]) ? unchecked((int)(-1)) : 0)) + { + Succeeded = false; + } + else + { + for (var i = 1; i < left.Length; i++) + { + if (result[i] != ((left[i] < right[i]) ? unchecked((int)(-1)) : 0)) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Sse2)}.{nameof(Sse2.CompareLessThan)}<Int32>: {method} failed:"); + Console.WriteLine($" left: ({string.Join(", ", left)})"); + Console.WriteLine($" right: ({string.Join(", ", right)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareLessThan.SByte.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareLessThan.SByte.cs new file mode 100644 index 0000000000..17eb6f00b6 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareLessThan.SByte.cs @@ -0,0 +1,315 @@ +// 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 CompareLessThanSByte() + { + var test = new SimpleBinaryOpTest__CompareLessThanSByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + // 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(); + + // 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(); + + // 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 works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + 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__CompareLessThanSByte + { + private const int VectorSize = 16; + private const int ElementCount = VectorSize / sizeof(SByte); + + private static SByte[] _data1 = new SByte[ElementCount]; + private static SByte[] _data2 = new SByte[ElementCount]; + + private static Vector128<SByte> _clsVar1; + private static Vector128<SByte> _clsVar2; + + private Vector128<SByte> _fld1; + private Vector128<SByte> _fld2; + + private SimpleBinaryOpTest__DataTable<SByte> _dataTable; + + static SimpleBinaryOpTest__CompareLessThanSByte() + { + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue)); _data2[i] = (sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<SByte>, byte>(ref _clsVar1), ref Unsafe.As<SByte, byte>(ref _data2[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<SByte>, byte>(ref _clsVar2), ref Unsafe.As<SByte, byte>(ref _data1[0]), VectorSize); + } + + public SimpleBinaryOpTest__CompareLessThanSByte() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue)); _data2[i] = (sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<SByte>, byte>(ref _fld1), ref Unsafe.As<SByte, byte>(ref _data1[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<SByte>, byte>(ref _fld2), ref Unsafe.As<SByte, byte>(ref _data2[0]), VectorSize); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue)); _data2[i] = (sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue)); } + _dataTable = new SimpleBinaryOpTest__DataTable<SByte>(_data1, _data2, new SByte[ElementCount], VectorSize); + } + + public bool IsSupported => Sse2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse2.CompareLessThan( + Unsafe.Read<Vector128<SByte>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<SByte>>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse2.CompareLessThan( + Sse2.LoadVector128((SByte*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((SByte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse2.CompareLessThan( + Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.CompareLessThan), new Type[] { typeof(Vector128<SByte>), typeof(Vector128<SByte>) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector128<SByte>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<SByte>>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<SByte>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.CompareLessThan), new Type[] { typeof(Vector128<SByte>), typeof(Vector128<SByte>) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((SByte*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((SByte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<SByte>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.CompareLessThan), new Type[] { typeof(Vector128<SByte>), typeof(Vector128<SByte>) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<SByte>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse2.CompareLessThan( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read<Vector128<SByte>>(_dataTable.inArray1Ptr); + var right = Unsafe.Read<Vector128<SByte>>(_dataTable.inArray2Ptr); + var result = Sse2.CompareLessThan(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((SByte*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((SByte*)(_dataTable.inArray2Ptr)); + var result = Sse2.CompareLessThan(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArray2Ptr)); + var result = Sse2.CompareLessThan(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__CompareLessThanSByte(); + var result = Sse2.CompareLessThan(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse2.CompareLessThan(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128<SByte> left, Vector128<SByte> right, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[ElementCount]; + SByte[] inArray2 = new SByte[ElementCount]; + SByte[] outArray = new SByte[ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<SByte, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[ElementCount]; + SByte[] inArray2 = new SByte[ElementCount]; + SByte[] outArray = new SByte[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<SByte, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<SByte, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<SByte, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(SByte[] left, SByte[] right, SByte[] result, [CallerMemberName] string method = "") + { + if (result[0] != ((left[0] < right[0]) ? unchecked((sbyte)(-1)) : 0)) + { + Succeeded = false; + } + else + { + for (var i = 1; i < left.Length; i++) + { + if (result[i] != ((left[i] < right[i]) ? unchecked((sbyte)(-1)) : 0)) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Sse2)}.{nameof(Sse2.CompareLessThan)}<SByte>: {method} failed:"); + Console.WriteLine($" left: ({string.Join(", ", left)})"); + Console.WriteLine($" right: ({string.Join(", ", right)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareLessThan.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareLessThan.cs deleted file mode 100644 index ad70faba3a..0000000000 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareLessThan.cs +++ /dev/null @@ -1,104 +0,0 @@ -// 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. -// - -using System; -using System.Runtime.Intrinsics.X86; -using System.Runtime.Intrinsics; - -namespace IntelHardwareIntrinsicTest -{ - internal static partial class Program - { - - const int Pass = 100; - const int Fail = 0; - - static unsafe int Main(string[] args) - { - int testResult = Pass; - int testsCount = 21; - string methodUnderTestName = nameof(Sse2.CompareLessThan); - - if (Sse2.IsSupported) - { - using (var doubleTable = TestTableSse2<double>.Create(testsCount)) - using (var intTable = TestTableSse2<int>.Create(testsCount)) - using (var shortTable = TestTableSse2<short>.Create(testsCount)) - using (var sbyteTable = TestTableSse2<sbyte>.Create(testsCount)) - { - for (int i = 0; i < testsCount; i++) - { - (Vector128<double>, Vector128<double>, Vector128<double>) value = doubleTable[i]; - var result = Sse2.CompareLessThan(value.Item1, value.Item2); - doubleTable.SetOutArray(result); - } - - for (int i = 0; i < testsCount; i++) - { - (Vector128<int>, Vector128<int>, Vector128<int>) value = intTable[i]; - var result = Sse2.CompareLessThan(value.Item1, value.Item2); - intTable.SetOutArray(result); - } - - for (int i = 0; i < testsCount; i++) - { - (Vector128<short>, Vector128<short>, Vector128<short>) value = shortTable[i]; - var result = Sse2.CompareLessThan(value.Item1, value.Item2); - shortTable.SetOutArray(result); - } - - for (int i = 0; i < testsCount; i++) - { - (Vector128<sbyte>, Vector128<sbyte>, Vector128<sbyte>) value = sbyteTable[i]; - var result = Sse2.CompareLessThan(value.Item1, value.Item2); - sbyteTable.SetOutArray(result); - } - - CheckMethod<double> checkDouble = (double x, double y, double z, ref double a) => - { - a = x < y ? BitConverter.Int64BitsToDouble(-1) : 0; - return BitConverter.DoubleToInt64Bits(a) == BitConverter.DoubleToInt64Bits(z); - }; - - if (!doubleTable.CheckResult(checkDouble)) - { - PrintError(doubleTable, methodUnderTestName, "(double x, double y, double z, ref double a) => (a = x < y ? BitConverter.Int64BitsToDouble(-1) : 0) == z", checkDouble); - testResult = Fail; - } - - CheckMethod<int> checkInt32 = (int x, int y, int z, ref int a) => (a = x < y ? -1 : 0) == z; - - if (!intTable.CheckResult(checkInt32)) - { - PrintError(intTable, methodUnderTestName, "(int x, int y, int z, ref int a) => (a = x < y ? -1 : 0) == z;", checkInt32); - testResult = Fail; - } - - CheckMethod<short> checkInt16 = (short x, short y, short z, ref short a) => (a = (short)(x < y ? -1 : 0)) == z; - - if (!shortTable.CheckResult(checkInt16)) - { - PrintError(shortTable, methodUnderTestName, "(short x, short y, short z, ref short a) => (a = (short)(x < y ? -1 : 0)) == z", checkInt16); - testResult = Fail; - } - - CheckMethod<sbyte> checkSByte = (sbyte x, sbyte y, sbyte z, ref sbyte a) => (a = (sbyte)(x < y ? -1 : 0)) == z; - - if (!sbyteTable.CheckResult(checkSByte)) - { - PrintError(sbyteTable, methodUnderTestName, "(sbyte x, sbyte y, sbyte z, ref sbyte a) => (a = (sbyte)(x < y ? -1 : 0)) == z", checkSByte); - testResult = Fail; - } - } - } - else - { - Console.WriteLine($"Sse2.IsSupported: {Sse2.IsSupported}, skipped tests of {typeof(Sse2)}.{methodUnderTestName}"); - } - - return testResult; - } - } -} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareLessThanOrEqual.Double.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareLessThanOrEqual.Double.cs new file mode 100644 index 0000000000..e8a2beb65f --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareLessThanOrEqual.Double.cs @@ -0,0 +1,315 @@ +// 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 CompareLessThanOrEqualDouble() + { + var test = new SimpleBinaryOpTest__CompareLessThanOrEqualDouble(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + // 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(); + + // 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(); + + // 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 works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + 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__CompareLessThanOrEqualDouble + { + private const int VectorSize = 16; + private const int ElementCount = VectorSize / sizeof(Double); + + private static Double[] _data1 = new Double[ElementCount]; + private static Double[] _data2 = new Double[ElementCount]; + + private static Vector128<Double> _clsVar1; + private static Vector128<Double> _clsVar2; + + private Vector128<Double> _fld1; + private Vector128<Double> _fld2; + + private SimpleBinaryOpTest__DataTable<Double> _dataTable; + + static SimpleBinaryOpTest__CompareLessThanOrEqualDouble() + { + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (double)(random.NextDouble()); _data2[i] = (double)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Double>, byte>(ref _clsVar1), ref Unsafe.As<Double, byte>(ref _data2[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Double>, byte>(ref _clsVar2), ref Unsafe.As<Double, byte>(ref _data1[0]), VectorSize); + } + + public SimpleBinaryOpTest__CompareLessThanOrEqualDouble() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (double)(random.NextDouble()); _data2[i] = (double)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Double>, byte>(ref _fld1), ref Unsafe.As<Double, byte>(ref _data1[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Double>, byte>(ref _fld2), ref Unsafe.As<Double, byte>(ref _data2[0]), VectorSize); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (double)(random.NextDouble()); _data2[i] = (double)(random.NextDouble()); } + _dataTable = new SimpleBinaryOpTest__DataTable<Double>(_data1, _data2, new Double[ElementCount], VectorSize); + } + + public bool IsSupported => Sse2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse2.CompareLessThanOrEqual( + Unsafe.Read<Vector128<Double>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<Double>>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse2.CompareLessThanOrEqual( + Sse2.LoadVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Double*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse2.CompareLessThanOrEqual( + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.CompareLessThanOrEqual), new Type[] { typeof(Vector128<Double>), typeof(Vector128<Double>) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector128<Double>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<Double>>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Double>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.CompareLessThanOrEqual), new Type[] { typeof(Vector128<Double>), typeof(Vector128<Double>) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Double*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Double>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.CompareLessThanOrEqual), new Type[] { typeof(Vector128<Double>), typeof(Vector128<Double>) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Double>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse2.CompareLessThanOrEqual( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read<Vector128<Double>>(_dataTable.inArray1Ptr); + var right = Unsafe.Read<Vector128<Double>>(_dataTable.inArray2Ptr); + var result = Sse2.CompareLessThanOrEqual(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((Double*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((Double*)(_dataTable.inArray2Ptr)); + var result = Sse2.CompareLessThanOrEqual(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray2Ptr)); + var result = Sse2.CompareLessThanOrEqual(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__CompareLessThanOrEqualDouble(); + var result = Sse2.CompareLessThanOrEqual(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse2.CompareLessThanOrEqual(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128<Double> left, Vector128<Double> right, void* result, [CallerMemberName] string method = "") + { + Double[] inArray1 = new Double[ElementCount]; + Double[] inArray2 = new Double[ElementCount]; + Double[] outArray = new Double[ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Double[] inArray1 = new Double[ElementCount]; + Double[] inArray2 = new Double[ElementCount]; + Double[] outArray = new Double[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Double[] left, Double[] right, Double[] result, [CallerMemberName] string method = "") + { + if (BitConverter.DoubleToInt64Bits(result[0]) != ((left[0] <= right[0]) ? -1 : 0)) + { + Succeeded = false; + } + else + { + for (var i = 1; i < left.Length; i++) + { + if (BitConverter.DoubleToInt64Bits(result[i]) != ((left[i] <= right[i]) ? -1 : 0)) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Sse2)}.{nameof(Sse2.CompareLessThanOrEqual)}<Double>: {method} failed:"); + Console.WriteLine($" left: ({string.Join(", ", left)})"); + Console.WriteLine($" right: ({string.Join(", ", right)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareLessThanOrEqual.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareLessThanOrEqual.cs deleted file mode 100644 index d56a55e29b..0000000000 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareLessThanOrEqual.cs +++ /dev/null @@ -1,55 +0,0 @@ -// 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. -// - -using System; -using System.Runtime.Intrinsics; -using System.Runtime.Intrinsics.X86; - -namespace IntelHardwareIntrinsicTest -{ - internal static partial class Program - { - private const int Pass = 100; - private const int Fail = 0; - - static unsafe int Main(string[] args) - { - int testResult = Pass; - int testsCount = 21; - string methodUnderTestName = nameof(Sse2.CompareLessThanOrEqual); - - if (Sse2.IsSupported) - { - using (var doubleTable = TestTableSse2<double>.Create(testsCount)) - { - for (int i = 0; i < testsCount; i++) - { - (Vector128<double>, Vector128<double>, Vector128<double>) value = doubleTable[i]; - var result = Sse2.CompareLessThanOrEqual(value.Item1, value.Item2); - doubleTable.SetOutArray(result); - } - - CheckMethod<double> checkDouble = (double x, double y, double z, ref double a) => - { - a = x <= y ? BitConverter.Int64BitsToDouble(-1) : 0; - return BitConverter.DoubleToInt64Bits(a) == BitConverter.DoubleToInt64Bits(z); - }; - - if (!doubleTable.CheckResult(checkDouble)) - { - PrintError(doubleTable, methodUnderTestName, "(x, y, z, ref a) => (a = x <= y ? double.NaN : 0) == z", checkDouble); - testResult = Fail; - } - } - } - else - { - Console.WriteLine($"Sse2.IsSupported: {Sse2.IsSupported}, skipped tests of {typeof(Sse2)}.{methodUnderTestName}"); - } - - return testResult; - } - } -} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareLessThanOrEqual_r.csproj b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareLessThanOrEqual_r.csproj deleted file mode 100644 index a183a38f0d..0000000000 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareLessThanOrEqual_r.csproj +++ /dev/null @@ -1,38 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" /> - <PropertyGroup> - <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> - <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> - <SchemaVersion>2.0</SchemaVersion> - <ProjectGuid>{398DEA1A-16E3-4EE8-8668-54DFB80EB7AB}</ProjectGuid> - <OutputType>Exe</OutputType> - <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> - <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir> - <AllowUnsafeBlocks>true</AllowUnsafeBlocks> - </PropertyGroup> - <!-- Default configurations to help VS understand the configurations --> - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> - </PropertyGroup> - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' " /> - <ItemGroup> - <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies"> - <Visible>False</Visible> - </CodeAnalysisDependentAssemblyPaths> - </ItemGroup> - <PropertyGroup> - <DebugType>None</DebugType> - <Optimize> - </Optimize> - </PropertyGroup> - <ItemGroup> - <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" /> - </ItemGroup> - <ItemGroup> - <Compile Include="CompareLessThanOrEqual.cs" /> - <Compile Include="TestTableSse2.cs" /> - </ItemGroup> - <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" /> - <PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' "> - </PropertyGroup> -</Project>
\ No newline at end of file diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareLessThanOrEqual_ro.csproj b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareLessThanOrEqual_ro.csproj deleted file mode 100644 index 04147332c9..0000000000 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareLessThanOrEqual_ro.csproj +++ /dev/null @@ -1,37 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" /> - <PropertyGroup> - <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> - <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> - <SchemaVersion>2.0</SchemaVersion> - <ProjectGuid>{3AC17539-DEBA-4FFB-BE4A-4FCB21C37294}</ProjectGuid> - <OutputType>Exe</OutputType> - <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> - <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir> - <AllowUnsafeBlocks>true</AllowUnsafeBlocks> - </PropertyGroup> - <!-- Default configurations to help VS understand the configurations --> - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> - </PropertyGroup> - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' " /> - <ItemGroup> - <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies"> - <Visible>False</Visible> - </CodeAnalysisDependentAssemblyPaths> - </ItemGroup> - <PropertyGroup> - <DebugType>None</DebugType> - <Optimize>True</Optimize> - </PropertyGroup> - <ItemGroup> - <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" /> - </ItemGroup> - <ItemGroup> - <Compile Include="CompareLessThanOrEqual.cs" /> - <Compile Include="TestTableSse2.cs" /> - </ItemGroup> - <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" /> - <PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' "> - </PropertyGroup> -</Project>
\ No newline at end of file diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareLessThan_r.csproj b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareLessThan_r.csproj deleted file mode 100644 index 4577a520d0..0000000000 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareLessThan_r.csproj +++ /dev/null @@ -1,38 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" /> - <PropertyGroup> - <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> - <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> - <SchemaVersion>2.0</SchemaVersion> - <ProjectGuid>{93E4851E-5200-4A1E-AC26-FD8B18476570}</ProjectGuid> - <OutputType>Exe</OutputType> - <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> - <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir> - <AllowUnsafeBlocks>true</AllowUnsafeBlocks> - </PropertyGroup> - <!-- Default configurations to help VS understand the configurations --> - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> - </PropertyGroup> - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' " /> - <ItemGroup> - <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies"> - <Visible>False</Visible> - </CodeAnalysisDependentAssemblyPaths> - </ItemGroup> - <PropertyGroup> - <DebugType>None</DebugType> - <Optimize> - </Optimize> - </PropertyGroup> - <ItemGroup> - <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" /> - </ItemGroup> - <ItemGroup> - <Compile Include="CompareLessThan.cs" /> - <Compile Include="TestTableSse2.cs" /> - </ItemGroup> - <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" /> - <PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' "> - </PropertyGroup> -</Project>
\ No newline at end of file diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareLessThan_ro.csproj b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareLessThan_ro.csproj deleted file mode 100644 index 4012f4e0b8..0000000000 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareLessThan_ro.csproj +++ /dev/null @@ -1,37 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" /> - <PropertyGroup> - <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> - <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> - <SchemaVersion>2.0</SchemaVersion> - <ProjectGuid>{EFB18286-69A8-4260-8AD9-94A576984ECB}</ProjectGuid> - <OutputType>Exe</OutputType> - <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> - <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir> - <AllowUnsafeBlocks>true</AllowUnsafeBlocks> - </PropertyGroup> - <!-- Default configurations to help VS understand the configurations --> - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> - </PropertyGroup> - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' " /> - <ItemGroup> - <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies"> - <Visible>False</Visible> - </CodeAnalysisDependentAssemblyPaths> - </ItemGroup> - <PropertyGroup> - <DebugType>None</DebugType> - <Optimize>True</Optimize> - </PropertyGroup> - <ItemGroup> - <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" /> - </ItemGroup> - <ItemGroup> - <Compile Include="CompareLessThan.cs" /> - <Compile Include="TestTableSse2.cs" /> - </ItemGroup> - <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" /> - <PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' "> - </PropertyGroup> -</Project>
\ No newline at end of file diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareNotEqual.Double.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareNotEqual.Double.cs new file mode 100644 index 0000000000..8f34fcc250 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareNotEqual.Double.cs @@ -0,0 +1,315 @@ +// 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 CompareNotEqualDouble() + { + var test = new SimpleBinaryOpTest__CompareNotEqualDouble(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + // 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(); + + // 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(); + + // 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 works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + 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__CompareNotEqualDouble + { + private const int VectorSize = 16; + private const int ElementCount = VectorSize / sizeof(Double); + + private static Double[] _data1 = new Double[ElementCount]; + private static Double[] _data2 = new Double[ElementCount]; + + private static Vector128<Double> _clsVar1; + private static Vector128<Double> _clsVar2; + + private Vector128<Double> _fld1; + private Vector128<Double> _fld2; + + private SimpleBinaryOpTest__DataTable<Double> _dataTable; + + static SimpleBinaryOpTest__CompareNotEqualDouble() + { + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (double)(random.NextDouble()); _data2[i] = (double)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Double>, byte>(ref _clsVar1), ref Unsafe.As<Double, byte>(ref _data2[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Double>, byte>(ref _clsVar2), ref Unsafe.As<Double, byte>(ref _data1[0]), VectorSize); + } + + public SimpleBinaryOpTest__CompareNotEqualDouble() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (double)(random.NextDouble()); _data2[i] = (double)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Double>, byte>(ref _fld1), ref Unsafe.As<Double, byte>(ref _data1[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Double>, byte>(ref _fld2), ref Unsafe.As<Double, byte>(ref _data2[0]), VectorSize); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (double)(random.NextDouble()); _data2[i] = (double)(random.NextDouble()); } + _dataTable = new SimpleBinaryOpTest__DataTable<Double>(_data1, _data2, new Double[ElementCount], VectorSize); + } + + public bool IsSupported => Sse2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse2.CompareNotEqual( + Unsafe.Read<Vector128<Double>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<Double>>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse2.CompareNotEqual( + Sse2.LoadVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Double*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse2.CompareNotEqual( + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.CompareNotEqual), new Type[] { typeof(Vector128<Double>), typeof(Vector128<Double>) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector128<Double>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<Double>>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Double>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.CompareNotEqual), new Type[] { typeof(Vector128<Double>), typeof(Vector128<Double>) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Double*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Double>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.CompareNotEqual), new Type[] { typeof(Vector128<Double>), typeof(Vector128<Double>) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Double>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse2.CompareNotEqual( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read<Vector128<Double>>(_dataTable.inArray1Ptr); + var right = Unsafe.Read<Vector128<Double>>(_dataTable.inArray2Ptr); + var result = Sse2.CompareNotEqual(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((Double*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((Double*)(_dataTable.inArray2Ptr)); + var result = Sse2.CompareNotEqual(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray2Ptr)); + var result = Sse2.CompareNotEqual(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__CompareNotEqualDouble(); + var result = Sse2.CompareNotEqual(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse2.CompareNotEqual(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128<Double> left, Vector128<Double> right, void* result, [CallerMemberName] string method = "") + { + Double[] inArray1 = new Double[ElementCount]; + Double[] inArray2 = new Double[ElementCount]; + Double[] outArray = new Double[ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Double[] inArray1 = new Double[ElementCount]; + Double[] inArray2 = new Double[ElementCount]; + Double[] outArray = new Double[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Double[] left, Double[] right, Double[] result, [CallerMemberName] string method = "") + { + if (BitConverter.DoubleToInt64Bits(result[0]) != ((left[0] != right[0]) ? -1 : 0)) + { + Succeeded = false; + } + else + { + for (var i = 1; i < left.Length; i++) + { + if (BitConverter.DoubleToInt64Bits(result[i]) != ((left[i] != right[i]) ? -1 : 0)) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Sse2)}.{nameof(Sse2.CompareNotEqual)}<Double>: {method} failed:"); + Console.WriteLine($" left: ({string.Join(", ", left)})"); + Console.WriteLine($" right: ({string.Join(", ", right)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareNotEqual.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareNotEqual.cs deleted file mode 100644 index 6a4615e2a2..0000000000 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareNotEqual.cs +++ /dev/null @@ -1,55 +0,0 @@ -// 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. -// - -using System; -using System.Runtime.Intrinsics; -using System.Runtime.Intrinsics.X86; - -namespace IntelHardwareIntrinsicTest -{ - internal static partial class Program - { - private const int Pass = 100; - private const int Fail = 0; - - static unsafe int Main(string[] args) - { - int testResult = Pass; - int testsCount = 21; - string methodUnderTestName = nameof(Sse2.CompareNotEqual); - - if (Sse2.IsSupported) - { - using (var doubleTable = TestTableSse2<double>.Create(testsCount)) - { - for (int i = 0; i < testsCount; i++) - { - (Vector128<double>, Vector128<double>, Vector128<double>) value = doubleTable[i]; - var result = Sse2.CompareNotEqual(value.Item1, value.Item2); - doubleTable.SetOutArray(result); - } - - CheckMethod<double> checkDouble = (double x, double y, double z, ref double a) => - { - a = x != y ? BitConverter.Int64BitsToDouble(-1) : 0; - return BitConverter.DoubleToInt64Bits(a) == BitConverter.DoubleToInt64Bits(z); - }; - - if (!doubleTable.CheckResult(checkDouble)) - { - PrintError(doubleTable, methodUnderTestName, "(x, y, z, ref a) => (a = x != y ? double.NaN : 0) == z", checkDouble); - testResult = Fail; - } - } - } - else - { - Console.WriteLine($"Sse2.IsSupported: {Sse2.IsSupported}, skipped tests of {typeof(Sse2)}.{methodUnderTestName}"); - } - - return testResult; - } - } -} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareNotEqual_r.csproj b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareNotEqual_r.csproj deleted file mode 100644 index b98123cbf8..0000000000 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareNotEqual_r.csproj +++ /dev/null @@ -1,38 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" /> - <PropertyGroup> - <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> - <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> - <SchemaVersion>2.0</SchemaVersion> - <ProjectGuid>{9E2D750B-1AD6-4CCB-8CEE-856A702714DB}</ProjectGuid> - <OutputType>Exe</OutputType> - <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> - <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir> - <AllowUnsafeBlocks>true</AllowUnsafeBlocks> - </PropertyGroup> - <!-- Default configurations to help VS understand the configurations --> - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> - </PropertyGroup> - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' " /> - <ItemGroup> - <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies"> - <Visible>False</Visible> - </CodeAnalysisDependentAssemblyPaths> - </ItemGroup> - <PropertyGroup> - <DebugType>None</DebugType> - <Optimize> - </Optimize> - </PropertyGroup> - <ItemGroup> - <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" /> - </ItemGroup> - <ItemGroup> - <Compile Include="CompareNotEqual.cs" /> - <Compile Include="TestTableSse2.cs" /> - </ItemGroup> - <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" /> - <PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' "> - </PropertyGroup> -</Project>
\ No newline at end of file diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareNotEqual_ro.csproj b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareNotEqual_ro.csproj deleted file mode 100644 index 341273a044..0000000000 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareNotEqual_ro.csproj +++ /dev/null @@ -1,37 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" /> - <PropertyGroup> - <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> - <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> - <SchemaVersion>2.0</SchemaVersion> - <ProjectGuid>{A51475EC-9B61-442A-B8E9-90817E8C5FF3}</ProjectGuid> - <OutputType>Exe</OutputType> - <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> - <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir> - <AllowUnsafeBlocks>true</AllowUnsafeBlocks> - </PropertyGroup> - <!-- Default configurations to help VS understand the configurations --> - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> - </PropertyGroup> - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' " /> - <ItemGroup> - <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies"> - <Visible>False</Visible> - </CodeAnalysisDependentAssemblyPaths> - </ItemGroup> - <PropertyGroup> - <DebugType>None</DebugType> - <Optimize>True</Optimize> - </PropertyGroup> - <ItemGroup> - <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" /> - </ItemGroup> - <ItemGroup> - <Compile Include="CompareNotEqual.cs" /> - <Compile Include="TestTableSse2.cs" /> - </ItemGroup> - <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" /> - <PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' "> - </PropertyGroup> -</Project>
\ No newline at end of file diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareNotGreaterThan.Double.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareNotGreaterThan.Double.cs new file mode 100644 index 0000000000..1aca451839 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareNotGreaterThan.Double.cs @@ -0,0 +1,315 @@ +// 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 CompareNotGreaterThanDouble() + { + var test = new SimpleBinaryOpTest__CompareNotGreaterThanDouble(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + // 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(); + + // 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(); + + // 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 works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + 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__CompareNotGreaterThanDouble + { + private const int VectorSize = 16; + private const int ElementCount = VectorSize / sizeof(Double); + + private static Double[] _data1 = new Double[ElementCount]; + private static Double[] _data2 = new Double[ElementCount]; + + private static Vector128<Double> _clsVar1; + private static Vector128<Double> _clsVar2; + + private Vector128<Double> _fld1; + private Vector128<Double> _fld2; + + private SimpleBinaryOpTest__DataTable<Double> _dataTable; + + static SimpleBinaryOpTest__CompareNotGreaterThanDouble() + { + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (double)(random.NextDouble()); _data2[i] = (double)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Double>, byte>(ref _clsVar1), ref Unsafe.As<Double, byte>(ref _data2[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Double>, byte>(ref _clsVar2), ref Unsafe.As<Double, byte>(ref _data1[0]), VectorSize); + } + + public SimpleBinaryOpTest__CompareNotGreaterThanDouble() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (double)(random.NextDouble()); _data2[i] = (double)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Double>, byte>(ref _fld1), ref Unsafe.As<Double, byte>(ref _data1[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Double>, byte>(ref _fld2), ref Unsafe.As<Double, byte>(ref _data2[0]), VectorSize); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (double)(random.NextDouble()); _data2[i] = (double)(random.NextDouble()); } + _dataTable = new SimpleBinaryOpTest__DataTable<Double>(_data1, _data2, new Double[ElementCount], VectorSize); + } + + public bool IsSupported => Sse2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse2.CompareNotGreaterThan( + Unsafe.Read<Vector128<Double>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<Double>>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse2.CompareNotGreaterThan( + Sse2.LoadVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Double*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse2.CompareNotGreaterThan( + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.CompareNotGreaterThan), new Type[] { typeof(Vector128<Double>), typeof(Vector128<Double>) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector128<Double>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<Double>>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Double>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.CompareNotGreaterThan), new Type[] { typeof(Vector128<Double>), typeof(Vector128<Double>) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Double*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Double>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.CompareNotGreaterThan), new Type[] { typeof(Vector128<Double>), typeof(Vector128<Double>) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Double>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse2.CompareNotGreaterThan( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read<Vector128<Double>>(_dataTable.inArray1Ptr); + var right = Unsafe.Read<Vector128<Double>>(_dataTable.inArray2Ptr); + var result = Sse2.CompareNotGreaterThan(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((Double*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((Double*)(_dataTable.inArray2Ptr)); + var result = Sse2.CompareNotGreaterThan(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray2Ptr)); + var result = Sse2.CompareNotGreaterThan(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__CompareNotGreaterThanDouble(); + var result = Sse2.CompareNotGreaterThan(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse2.CompareNotGreaterThan(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128<Double> left, Vector128<Double> right, void* result, [CallerMemberName] string method = "") + { + Double[] inArray1 = new Double[ElementCount]; + Double[] inArray2 = new Double[ElementCount]; + Double[] outArray = new Double[ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Double[] inArray1 = new Double[ElementCount]; + Double[] inArray2 = new Double[ElementCount]; + Double[] outArray = new Double[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Double[] left, Double[] right, Double[] result, [CallerMemberName] string method = "") + { + if (BitConverter.DoubleToInt64Bits(result[0]) != (!(left[0] > right[0]) ? -1 : 0)) + { + Succeeded = false; + } + else + { + for (var i = 1; i < left.Length; i++) + { + if (BitConverter.DoubleToInt64Bits(result[i]) != (!(left[i] > right[i]) ? -1 : 0)) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Sse2)}.{nameof(Sse2.CompareNotGreaterThan)}<Double>: {method} failed:"); + Console.WriteLine($" left: ({string.Join(", ", left)})"); + Console.WriteLine($" right: ({string.Join(", ", right)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareNotGreaterThan.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareNotGreaterThan.cs deleted file mode 100644 index 6fbeef8b3f..0000000000 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareNotGreaterThan.cs +++ /dev/null @@ -1,56 +0,0 @@ -// 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. -// - -using System; -using System.Runtime.Intrinsics; -using System.Runtime.Intrinsics.X86; - -namespace IntelHardwareIntrinsicTest -{ - internal static partial class Program - { - private const int Pass = 100; - private const int Fail = 0; - - static unsafe int Main(string[] args) - { - int testResult = Pass; - int testsCount = 21; - string methodUnderTestName = nameof(Sse2.CompareNotGreaterThan); - - if (Sse2.IsSupported) - { - using (var doubleTable = TestTableSse2<double>.Create(testsCount)) - { - for (int i = 0; i < testsCount; i++) - { - (Vector128<double>, Vector128<double>, Vector128<double>) value = doubleTable[i]; - var result = Sse2.CompareNotGreaterThan(value.Item1, value.Item2); - doubleTable.SetOutArray(result); - } - - CheckMethod<double> checkDouble = (double x, double y, double z, ref double a) => - { - // Exactly after Intel manual - a = !(x > y) ? BitConverter.Int64BitsToDouble(-1) : 0; - return BitConverter.DoubleToInt64Bits(a) == BitConverter.DoubleToInt64Bits(z); - }; - - if (!doubleTable.CheckResult(checkDouble)) - { - PrintError(doubleTable, methodUnderTestName, "(x, y, z, ref a) => (a = !(x > y) ? double.NaN : 0) == z", checkDouble); - testResult = Fail; - } - } - } - else - { - Console.WriteLine($"Sse2.IsSupported: {Sse2.IsSupported}, skipped tests of {typeof(Sse2)}.{methodUnderTestName}"); - } - - return testResult; - } - } -} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareNotGreaterThanOrEqual.Double.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareNotGreaterThanOrEqual.Double.cs new file mode 100644 index 0000000000..9b34b59a4e --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareNotGreaterThanOrEqual.Double.cs @@ -0,0 +1,315 @@ +// 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 CompareNotGreaterThanOrEqualDouble() + { + var test = new SimpleBinaryOpTest__CompareNotGreaterThanOrEqualDouble(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + // 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(); + + // 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(); + + // 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 works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + 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__CompareNotGreaterThanOrEqualDouble + { + private const int VectorSize = 16; + private const int ElementCount = VectorSize / sizeof(Double); + + private static Double[] _data1 = new Double[ElementCount]; + private static Double[] _data2 = new Double[ElementCount]; + + private static Vector128<Double> _clsVar1; + private static Vector128<Double> _clsVar2; + + private Vector128<Double> _fld1; + private Vector128<Double> _fld2; + + private SimpleBinaryOpTest__DataTable<Double> _dataTable; + + static SimpleBinaryOpTest__CompareNotGreaterThanOrEqualDouble() + { + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (double)(random.NextDouble()); _data2[i] = (double)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Double>, byte>(ref _clsVar1), ref Unsafe.As<Double, byte>(ref _data2[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Double>, byte>(ref _clsVar2), ref Unsafe.As<Double, byte>(ref _data1[0]), VectorSize); + } + + public SimpleBinaryOpTest__CompareNotGreaterThanOrEqualDouble() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (double)(random.NextDouble()); _data2[i] = (double)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Double>, byte>(ref _fld1), ref Unsafe.As<Double, byte>(ref _data1[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Double>, byte>(ref _fld2), ref Unsafe.As<Double, byte>(ref _data2[0]), VectorSize); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (double)(random.NextDouble()); _data2[i] = (double)(random.NextDouble()); } + _dataTable = new SimpleBinaryOpTest__DataTable<Double>(_data1, _data2, new Double[ElementCount], VectorSize); + } + + public bool IsSupported => Sse2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse2.CompareNotGreaterThanOrEqual( + Unsafe.Read<Vector128<Double>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<Double>>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse2.CompareNotGreaterThanOrEqual( + Sse2.LoadVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Double*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse2.CompareNotGreaterThanOrEqual( + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.CompareNotGreaterThanOrEqual), new Type[] { typeof(Vector128<Double>), typeof(Vector128<Double>) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector128<Double>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<Double>>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Double>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.CompareNotGreaterThanOrEqual), new Type[] { typeof(Vector128<Double>), typeof(Vector128<Double>) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Double*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Double>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.CompareNotGreaterThanOrEqual), new Type[] { typeof(Vector128<Double>), typeof(Vector128<Double>) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Double>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse2.CompareNotGreaterThanOrEqual( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read<Vector128<Double>>(_dataTable.inArray1Ptr); + var right = Unsafe.Read<Vector128<Double>>(_dataTable.inArray2Ptr); + var result = Sse2.CompareNotGreaterThanOrEqual(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((Double*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((Double*)(_dataTable.inArray2Ptr)); + var result = Sse2.CompareNotGreaterThanOrEqual(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray2Ptr)); + var result = Sse2.CompareNotGreaterThanOrEqual(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__CompareNotGreaterThanOrEqualDouble(); + var result = Sse2.CompareNotGreaterThanOrEqual(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse2.CompareNotGreaterThanOrEqual(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128<Double> left, Vector128<Double> right, void* result, [CallerMemberName] string method = "") + { + Double[] inArray1 = new Double[ElementCount]; + Double[] inArray2 = new Double[ElementCount]; + Double[] outArray = new Double[ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Double[] inArray1 = new Double[ElementCount]; + Double[] inArray2 = new Double[ElementCount]; + Double[] outArray = new Double[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Double[] left, Double[] right, Double[] result, [CallerMemberName] string method = "") + { + if (BitConverter.DoubleToInt64Bits(result[0]) != (!(left[0] >= right[0]) ? -1 : 0)) + { + Succeeded = false; + } + else + { + for (var i = 1; i < left.Length; i++) + { + if (BitConverter.DoubleToInt64Bits(result[i]) != (!(left[i] >= right[i]) ? -1 : 0)) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Sse2)}.{nameof(Sse2.CompareNotGreaterThanOrEqual)}<Double>: {method} failed:"); + Console.WriteLine($" left: ({string.Join(", ", left)})"); + Console.WriteLine($" right: ({string.Join(", ", right)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareNotGreaterThanOrEqual.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareNotGreaterThanOrEqual.cs deleted file mode 100644 index 42b8f27798..0000000000 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareNotGreaterThanOrEqual.cs +++ /dev/null @@ -1,55 +0,0 @@ -// 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. -// - -using System; -using System.Runtime.Intrinsics; -using System.Runtime.Intrinsics.X86; - -namespace IntelHardwareIntrinsicTest -{ - internal static partial class Program - { - private const int Pass = 100; - private const int Fail = 0; - - static unsafe int Main(string[] args) - { - int testResult = Pass; - int testsCount = 21; - string methodUnderTestName = nameof(Sse2.CompareNotGreaterThanOrEqual); - - if (Sse2.IsSupported) - { - using (var doubleTable = TestTableSse2<double>.Create(testsCount)) - { - for (int i = 0; i < testsCount; i++) - { - (Vector128<double>, Vector128<double>, Vector128<double>) value = doubleTable[i]; - var result = Sse2.CompareNotGreaterThanOrEqual(value.Item1, value.Item2); - doubleTable.SetOutArray(result); - } - - CheckMethod<double> checkDouble = (double x, double y, double z, ref double a) => - { - a = !(x >= y) ? BitConverter.Int64BitsToDouble(-1) : 0; - return BitConverter.DoubleToInt64Bits(a) == BitConverter.DoubleToInt64Bits(z); - }; - - if (!doubleTable.CheckResult(checkDouble)) - { - PrintError(doubleTable, methodUnderTestName, "(x, y, z, ref a) => (a = !(x >= y) ? double.NaN : 0) == z", checkDouble); - testResult = Fail; - } - } - } - else - { - Console.WriteLine($"Sse2.IsSupported: {Sse2.IsSupported}, skipped tests of {typeof(Sse2)}.{methodUnderTestName}"); - } - - return testResult; - } - } -} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareNotGreaterThanOrEqual_r.csproj b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareNotGreaterThanOrEqual_r.csproj deleted file mode 100644 index 841a9b5a7d..0000000000 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareNotGreaterThanOrEqual_r.csproj +++ /dev/null @@ -1,38 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" /> - <PropertyGroup> - <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> - <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> - <SchemaVersion>2.0</SchemaVersion> - <ProjectGuid>{9719321A-FA33-43E6-B01E-102879E77321}</ProjectGuid> - <OutputType>Exe</OutputType> - <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> - <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir> - <AllowUnsafeBlocks>true</AllowUnsafeBlocks> - </PropertyGroup> - <!-- Default configurations to help VS understand the configurations --> - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> - </PropertyGroup> - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' " /> - <ItemGroup> - <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies"> - <Visible>False</Visible> - </CodeAnalysisDependentAssemblyPaths> - </ItemGroup> - <PropertyGroup> - <DebugType>None</DebugType> - <Optimize> - </Optimize> - </PropertyGroup> - <ItemGroup> - <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" /> - </ItemGroup> - <ItemGroup> - <Compile Include="CompareNotGreaterThanOrEqual.cs" /> - <Compile Include="TestTableSse2.cs" /> - </ItemGroup> - <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" /> - <PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' "> - </PropertyGroup> -</Project>
\ No newline at end of file diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareNotGreaterThanOrEqual_ro.csproj b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareNotGreaterThanOrEqual_ro.csproj deleted file mode 100644 index 96d983e583..0000000000 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareNotGreaterThanOrEqual_ro.csproj +++ /dev/null @@ -1,37 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" /> - <PropertyGroup> - <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> - <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> - <SchemaVersion>2.0</SchemaVersion> - <ProjectGuid>{93C1DB28-D5A7-493D-8017-9E028D39E025}</ProjectGuid> - <OutputType>Exe</OutputType> - <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> - <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir> - <AllowUnsafeBlocks>true</AllowUnsafeBlocks> - </PropertyGroup> - <!-- Default configurations to help VS understand the configurations --> - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> - </PropertyGroup> - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' " /> - <ItemGroup> - <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies"> - <Visible>False</Visible> - </CodeAnalysisDependentAssemblyPaths> - </ItemGroup> - <PropertyGroup> - <DebugType>None</DebugType> - <Optimize>True</Optimize> - </PropertyGroup> - <ItemGroup> - <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" /> - </ItemGroup> - <ItemGroup> - <Compile Include="CompareNotGreaterThanOrEqual.cs" /> - <Compile Include="TestTableSse2.cs" /> - </ItemGroup> - <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" /> - <PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' "> - </PropertyGroup> -</Project>
\ No newline at end of file diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareNotGreaterThan_r.csproj b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareNotGreaterThan_r.csproj deleted file mode 100644 index 3db7ae5e24..0000000000 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareNotGreaterThan_r.csproj +++ /dev/null @@ -1,38 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" /> - <PropertyGroup> - <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> - <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> - <SchemaVersion>2.0</SchemaVersion> - <ProjectGuid>{CE864D5D-9D54-4000-A5BE-EC7052673CE5}</ProjectGuid> - <OutputType>Exe</OutputType> - <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> - <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir> - <AllowUnsafeBlocks>true</AllowUnsafeBlocks> - </PropertyGroup> - <!-- Default configurations to help VS understand the configurations --> - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> - </PropertyGroup> - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' " /> - <ItemGroup> - <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies"> - <Visible>False</Visible> - </CodeAnalysisDependentAssemblyPaths> - </ItemGroup> - <PropertyGroup> - <DebugType>None</DebugType> - <Optimize> - </Optimize> - </PropertyGroup> - <ItemGroup> - <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" /> - </ItemGroup> - <ItemGroup> - <Compile Include="CompareNotGreaterThan.cs" /> - <Compile Include="TestTableSse2.cs" /> - </ItemGroup> - <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" /> - <PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' "> - </PropertyGroup> -</Project>
\ No newline at end of file diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareNotGreaterThan_ro.csproj b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareNotGreaterThan_ro.csproj deleted file mode 100644 index 16b5b586ce..0000000000 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareNotGreaterThan_ro.csproj +++ /dev/null @@ -1,37 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" /> - <PropertyGroup> - <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> - <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> - <SchemaVersion>2.0</SchemaVersion> - <ProjectGuid>{8B32892C-136B-4809-A082-F4EEF0FD0A8F}</ProjectGuid> - <OutputType>Exe</OutputType> - <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> - <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir> - <AllowUnsafeBlocks>true</AllowUnsafeBlocks> - </PropertyGroup> - <!-- Default configurations to help VS understand the configurations --> - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> - </PropertyGroup> - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' " /> - <ItemGroup> - <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies"> - <Visible>False</Visible> - </CodeAnalysisDependentAssemblyPaths> - </ItemGroup> - <PropertyGroup> - <DebugType>None</DebugType> - <Optimize>True</Optimize> - </PropertyGroup> - <ItemGroup> - <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" /> - </ItemGroup> - <ItemGroup> - <Compile Include="CompareNotGreaterThan.cs" /> - <Compile Include="TestTableSse2.cs" /> - </ItemGroup> - <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" /> - <PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' "> - </PropertyGroup> -</Project>
\ No newline at end of file diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareNotLessThan.Double.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareNotLessThan.Double.cs new file mode 100644 index 0000000000..d2a124fa83 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareNotLessThan.Double.cs @@ -0,0 +1,315 @@ +// 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 CompareNotLessThanDouble() + { + var test = new SimpleBinaryOpTest__CompareNotLessThanDouble(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + // 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(); + + // 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(); + + // 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 works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + 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__CompareNotLessThanDouble + { + private const int VectorSize = 16; + private const int ElementCount = VectorSize / sizeof(Double); + + private static Double[] _data1 = new Double[ElementCount]; + private static Double[] _data2 = new Double[ElementCount]; + + private static Vector128<Double> _clsVar1; + private static Vector128<Double> _clsVar2; + + private Vector128<Double> _fld1; + private Vector128<Double> _fld2; + + private SimpleBinaryOpTest__DataTable<Double> _dataTable; + + static SimpleBinaryOpTest__CompareNotLessThanDouble() + { + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (double)(random.NextDouble()); _data2[i] = (double)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Double>, byte>(ref _clsVar1), ref Unsafe.As<Double, byte>(ref _data2[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Double>, byte>(ref _clsVar2), ref Unsafe.As<Double, byte>(ref _data1[0]), VectorSize); + } + + public SimpleBinaryOpTest__CompareNotLessThanDouble() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (double)(random.NextDouble()); _data2[i] = (double)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Double>, byte>(ref _fld1), ref Unsafe.As<Double, byte>(ref _data1[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Double>, byte>(ref _fld2), ref Unsafe.As<Double, byte>(ref _data2[0]), VectorSize); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (double)(random.NextDouble()); _data2[i] = (double)(random.NextDouble()); } + _dataTable = new SimpleBinaryOpTest__DataTable<Double>(_data1, _data2, new Double[ElementCount], VectorSize); + } + + public bool IsSupported => Sse2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse2.CompareNotLessThan( + Unsafe.Read<Vector128<Double>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<Double>>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse2.CompareNotLessThan( + Sse2.LoadVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Double*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse2.CompareNotLessThan( + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.CompareNotLessThan), new Type[] { typeof(Vector128<Double>), typeof(Vector128<Double>) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector128<Double>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<Double>>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Double>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.CompareNotLessThan), new Type[] { typeof(Vector128<Double>), typeof(Vector128<Double>) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Double*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Double>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.CompareNotLessThan), new Type[] { typeof(Vector128<Double>), typeof(Vector128<Double>) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Double>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse2.CompareNotLessThan( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read<Vector128<Double>>(_dataTable.inArray1Ptr); + var right = Unsafe.Read<Vector128<Double>>(_dataTable.inArray2Ptr); + var result = Sse2.CompareNotLessThan(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((Double*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((Double*)(_dataTable.inArray2Ptr)); + var result = Sse2.CompareNotLessThan(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray2Ptr)); + var result = Sse2.CompareNotLessThan(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__CompareNotLessThanDouble(); + var result = Sse2.CompareNotLessThan(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse2.CompareNotLessThan(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128<Double> left, Vector128<Double> right, void* result, [CallerMemberName] string method = "") + { + Double[] inArray1 = new Double[ElementCount]; + Double[] inArray2 = new Double[ElementCount]; + Double[] outArray = new Double[ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Double[] inArray1 = new Double[ElementCount]; + Double[] inArray2 = new Double[ElementCount]; + Double[] outArray = new Double[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Double[] left, Double[] right, Double[] result, [CallerMemberName] string method = "") + { + if (BitConverter.DoubleToInt64Bits(result[0]) != (!(left[0] < right[0]) ? -1 : 0)) + { + Succeeded = false; + } + else + { + for (var i = 1; i < left.Length; i++) + { + if (BitConverter.DoubleToInt64Bits(result[i]) != (!(left[i] < right[i]) ? -1 : 0)) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Sse2)}.{nameof(Sse2.CompareNotLessThan)}<Double>: {method} failed:"); + Console.WriteLine($" left: ({string.Join(", ", left)})"); + Console.WriteLine($" right: ({string.Join(", ", right)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareNotLessThan.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareNotLessThan.cs deleted file mode 100644 index cf48c68155..0000000000 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareNotLessThan.cs +++ /dev/null @@ -1,55 +0,0 @@ -// 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. -// - -using System; -using System.Runtime.Intrinsics; -using System.Runtime.Intrinsics.X86; - -namespace IntelHardwareIntrinsicTest -{ - internal static partial class Program - { - private const int Pass = 100; - private const int Fail = 0; - - static unsafe int Main(string[] args) - { - int testResult = Pass; - int testsCount = 21; - string methodUnderTestName = nameof(Sse2.CompareNotLessThan); - - if (Sse2.IsSupported) - { - using (var doubleTable = TestTableSse2<double>.Create(testsCount)) - { - for (int i = 0; i < testsCount; i++) - { - (Vector128<double>, Vector128<double>, Vector128<double>) value = doubleTable[i]; - var result = Sse2.CompareNotLessThan(value.Item1, value.Item2); - doubleTable.SetOutArray(result); - } - - CheckMethod<double> checkDouble = (double x, double y, double z, ref double a) => - { - a = !(x < y) ? BitConverter.Int64BitsToDouble(-1) : 0; - return BitConverter.DoubleToInt64Bits(a) == BitConverter.DoubleToInt64Bits(z); - }; - - if (!doubleTable.CheckResult(checkDouble)) - { - PrintError(doubleTable, methodUnderTestName, "(x, y, z, ref a) => (a = !(x < y) ? double.NaN : 0) == z", checkDouble); - testResult = Fail; - } - } - } - else - { - Console.WriteLine($"Sse2.IsSupported: {Sse2.IsSupported}, skipped tests of {typeof(Sse2)}.{methodUnderTestName}"); - } - - return testResult; - } - } -} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareNotLessThanOrEqual.Double.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareNotLessThanOrEqual.Double.cs new file mode 100644 index 0000000000..d889a84d01 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareNotLessThanOrEqual.Double.cs @@ -0,0 +1,315 @@ +// 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 CompareNotLessThanOrEqualDouble() + { + var test = new SimpleBinaryOpTest__CompareNotLessThanOrEqualDouble(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + // 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(); + + // 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(); + + // 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 works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + 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__CompareNotLessThanOrEqualDouble + { + private const int VectorSize = 16; + private const int ElementCount = VectorSize / sizeof(Double); + + private static Double[] _data1 = new Double[ElementCount]; + private static Double[] _data2 = new Double[ElementCount]; + + private static Vector128<Double> _clsVar1; + private static Vector128<Double> _clsVar2; + + private Vector128<Double> _fld1; + private Vector128<Double> _fld2; + + private SimpleBinaryOpTest__DataTable<Double> _dataTable; + + static SimpleBinaryOpTest__CompareNotLessThanOrEqualDouble() + { + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (double)(random.NextDouble()); _data2[i] = (double)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Double>, byte>(ref _clsVar1), ref Unsafe.As<Double, byte>(ref _data2[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Double>, byte>(ref _clsVar2), ref Unsafe.As<Double, byte>(ref _data1[0]), VectorSize); + } + + public SimpleBinaryOpTest__CompareNotLessThanOrEqualDouble() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (double)(random.NextDouble()); _data2[i] = (double)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Double>, byte>(ref _fld1), ref Unsafe.As<Double, byte>(ref _data1[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Double>, byte>(ref _fld2), ref Unsafe.As<Double, byte>(ref _data2[0]), VectorSize); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (double)(random.NextDouble()); _data2[i] = (double)(random.NextDouble()); } + _dataTable = new SimpleBinaryOpTest__DataTable<Double>(_data1, _data2, new Double[ElementCount], VectorSize); + } + + public bool IsSupported => Sse2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse2.CompareNotLessThanOrEqual( + Unsafe.Read<Vector128<Double>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<Double>>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse2.CompareNotLessThanOrEqual( + Sse2.LoadVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Double*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse2.CompareNotLessThanOrEqual( + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.CompareNotLessThanOrEqual), new Type[] { typeof(Vector128<Double>), typeof(Vector128<Double>) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector128<Double>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<Double>>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Double>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.CompareNotLessThanOrEqual), new Type[] { typeof(Vector128<Double>), typeof(Vector128<Double>) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Double*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Double>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.CompareNotLessThanOrEqual), new Type[] { typeof(Vector128<Double>), typeof(Vector128<Double>) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Double>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse2.CompareNotLessThanOrEqual( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read<Vector128<Double>>(_dataTable.inArray1Ptr); + var right = Unsafe.Read<Vector128<Double>>(_dataTable.inArray2Ptr); + var result = Sse2.CompareNotLessThanOrEqual(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((Double*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((Double*)(_dataTable.inArray2Ptr)); + var result = Sse2.CompareNotLessThanOrEqual(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray2Ptr)); + var result = Sse2.CompareNotLessThanOrEqual(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__CompareNotLessThanOrEqualDouble(); + var result = Sse2.CompareNotLessThanOrEqual(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse2.CompareNotLessThanOrEqual(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128<Double> left, Vector128<Double> right, void* result, [CallerMemberName] string method = "") + { + Double[] inArray1 = new Double[ElementCount]; + Double[] inArray2 = new Double[ElementCount]; + Double[] outArray = new Double[ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Double[] inArray1 = new Double[ElementCount]; + Double[] inArray2 = new Double[ElementCount]; + Double[] outArray = new Double[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Double[] left, Double[] right, Double[] result, [CallerMemberName] string method = "") + { + if (BitConverter.DoubleToInt64Bits(result[0]) != (!(left[0] <= right[0]) ? -1 : 0)) + { + Succeeded = false; + } + else + { + for (var i = 1; i < left.Length; i++) + { + if (BitConverter.DoubleToInt64Bits(result[i]) != (!(left[i] <= right[i]) ? -1 : 0)) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Sse2)}.{nameof(Sse2.CompareNotLessThanOrEqual)}<Double>: {method} failed:"); + Console.WriteLine($" left: ({string.Join(", ", left)})"); + Console.WriteLine($" right: ({string.Join(", ", right)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareNotLessThanOrEqual.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareNotLessThanOrEqual.cs deleted file mode 100644 index 2862717dbf..0000000000 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareNotLessThanOrEqual.cs +++ /dev/null @@ -1,55 +0,0 @@ -// 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. -// - -using System; -using System.Runtime.Intrinsics; -using System.Runtime.Intrinsics.X86; - -namespace IntelHardwareIntrinsicTest -{ - internal static partial class Program - { - private const int Pass = 100; - private const int Fail = 0; - - static unsafe int Main(string[] args) - { - int testResult = Pass; - int testsCount = 21; - string methodUnderTestName = nameof(Sse2.CompareNotLessThanOrEqual); - - if (Sse2.IsSupported) - { - using (var doubleTable = TestTableSse2<double>.Create(testsCount)) - { - for (int i = 0; i < testsCount; i++) - { - (Vector128<double>, Vector128<double>, Vector128<double>) value = doubleTable[i]; - var result = Sse2.CompareNotLessThanOrEqual(value.Item1, value.Item2); - doubleTable.SetOutArray(result); - } - - CheckMethod<double> checkDouble = (double x, double y, double z, ref double a) => - { - a = !(x <= y) ? BitConverter.Int64BitsToDouble(-1) : 0; - return BitConverter.DoubleToInt64Bits(a) == BitConverter.DoubleToInt64Bits(z); - }; - - if (!doubleTable.CheckResult(checkDouble)) - { - PrintError(doubleTable, methodUnderTestName, "(x, y, z, ref a) => (a = !(x <= y) ? double.NaN : 0) == z", checkDouble); - testResult = Fail; - } - } - } - else - { - Console.WriteLine($"Sse2.IsSupported: {Sse2.IsSupported}, skipped tests of {typeof(Sse2)}.{methodUnderTestName}"); - } - - return testResult; - } - } -} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareNotLessThanOrEqual_r.csproj b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareNotLessThanOrEqual_r.csproj deleted file mode 100644 index 6f02e3c022..0000000000 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareNotLessThanOrEqual_r.csproj +++ /dev/null @@ -1,38 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" /> - <PropertyGroup> - <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> - <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> - <SchemaVersion>2.0</SchemaVersion> - <ProjectGuid>{608FCA63-FF4F-4A38-9503-9CF51D291BAB}</ProjectGuid> - <OutputType>Exe</OutputType> - <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> - <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir> - <AllowUnsafeBlocks>true</AllowUnsafeBlocks> - </PropertyGroup> - <!-- Default configurations to help VS understand the configurations --> - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> - </PropertyGroup> - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' " /> - <ItemGroup> - <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies"> - <Visible>False</Visible> - </CodeAnalysisDependentAssemblyPaths> - </ItemGroup> - <PropertyGroup> - <DebugType>None</DebugType> - <Optimize> - </Optimize> - </PropertyGroup> - <ItemGroup> - <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" /> - </ItemGroup> - <ItemGroup> - <Compile Include="CompareNotLessThanOrEqual.cs" /> - <Compile Include="TestTableSse2.cs" /> - </ItemGroup> - <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" /> - <PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' "> - </PropertyGroup> -</Project>
\ No newline at end of file diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareNotLessThanOrEqual_ro.csproj b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareNotLessThanOrEqual_ro.csproj deleted file mode 100644 index 2fb947b06b..0000000000 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareNotLessThanOrEqual_ro.csproj +++ /dev/null @@ -1,37 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" /> - <PropertyGroup> - <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> - <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> - <SchemaVersion>2.0</SchemaVersion> - <ProjectGuid>{D61F7DC7-97A3-4A5A-8A49-B80195B7EBFA}</ProjectGuid> - <OutputType>Exe</OutputType> - <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> - <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir> - <AllowUnsafeBlocks>true</AllowUnsafeBlocks> - </PropertyGroup> - <!-- Default configurations to help VS understand the configurations --> - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> - </PropertyGroup> - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' " /> - <ItemGroup> - <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies"> - <Visible>False</Visible> - </CodeAnalysisDependentAssemblyPaths> - </ItemGroup> - <PropertyGroup> - <DebugType>None</DebugType> - <Optimize>True</Optimize> - </PropertyGroup> - <ItemGroup> - <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" /> - </ItemGroup> - <ItemGroup> - <Compile Include="CompareNotLessThanOrEqual.cs" /> - <Compile Include="TestTableSse2.cs" /> - </ItemGroup> - <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" /> - <PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' "> - </PropertyGroup> -</Project>
\ No newline at end of file diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareNotLessThan_r.csproj b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareNotLessThan_r.csproj deleted file mode 100644 index 1a3549a24d..0000000000 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareNotLessThan_r.csproj +++ /dev/null @@ -1,38 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" /> - <PropertyGroup> - <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> - <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> - <SchemaVersion>2.0</SchemaVersion> - <ProjectGuid>{BF772C6E-6EA2-4649-9618-D3DB0AE49F41}</ProjectGuid> - <OutputType>Exe</OutputType> - <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> - <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir> - <AllowUnsafeBlocks>true</AllowUnsafeBlocks> - </PropertyGroup> - <!-- Default configurations to help VS understand the configurations --> - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> - </PropertyGroup> - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' " /> - <ItemGroup> - <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies"> - <Visible>False</Visible> - </CodeAnalysisDependentAssemblyPaths> - </ItemGroup> - <PropertyGroup> - <DebugType>None</DebugType> - <Optimize> - </Optimize> - </PropertyGroup> - <ItemGroup> - <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" /> - </ItemGroup> - <ItemGroup> - <Compile Include="CompareNotLessThan.cs" /> - <Compile Include="TestTableSse2.cs" /> - </ItemGroup> - <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" /> - <PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' "> - </PropertyGroup> -</Project>
\ No newline at end of file diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareNotLessThan_ro.csproj b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareNotLessThan_ro.csproj deleted file mode 100644 index 61d7742464..0000000000 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareNotLessThan_ro.csproj +++ /dev/null @@ -1,37 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" /> - <PropertyGroup> - <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> - <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> - <SchemaVersion>2.0</SchemaVersion> - <ProjectGuid>{44063F5C-8943-4FC0-AEDF-45ED4A744CA9}</ProjectGuid> - <OutputType>Exe</OutputType> - <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> - <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir> - <AllowUnsafeBlocks>true</AllowUnsafeBlocks> - </PropertyGroup> - <!-- Default configurations to help VS understand the configurations --> - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> - </PropertyGroup> - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' " /> - <ItemGroup> - <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies"> - <Visible>False</Visible> - </CodeAnalysisDependentAssemblyPaths> - </ItemGroup> - <PropertyGroup> - <DebugType>None</DebugType> - <Optimize>True</Optimize> - </PropertyGroup> - <ItemGroup> - <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" /> - </ItemGroup> - <ItemGroup> - <Compile Include="CompareNotLessThan.cs" /> - <Compile Include="TestTableSse2.cs" /> - </ItemGroup> - <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" /> - <PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' "> - </PropertyGroup> -</Project>
\ No newline at end of file diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareOrdered.Double.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareOrdered.Double.cs new file mode 100644 index 0000000000..a26d95d09d --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareOrdered.Double.cs @@ -0,0 +1,315 @@ +// 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 CompareOrderedDouble() + { + var test = new SimpleBinaryOpTest__CompareOrderedDouble(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + // 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(); + + // 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(); + + // 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 works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + 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__CompareOrderedDouble + { + private const int VectorSize = 16; + private const int ElementCount = VectorSize / sizeof(Double); + + private static Double[] _data1 = new Double[ElementCount]; + private static Double[] _data2 = new Double[ElementCount]; + + private static Vector128<Double> _clsVar1; + private static Vector128<Double> _clsVar2; + + private Vector128<Double> _fld1; + private Vector128<Double> _fld2; + + private SimpleBinaryOpTest__DataTable<Double> _dataTable; + + static SimpleBinaryOpTest__CompareOrderedDouble() + { + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (double)(random.NextDouble()); _data2[i] = (double)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Double>, byte>(ref _clsVar1), ref Unsafe.As<Double, byte>(ref _data2[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Double>, byte>(ref _clsVar2), ref Unsafe.As<Double, byte>(ref _data1[0]), VectorSize); + } + + public SimpleBinaryOpTest__CompareOrderedDouble() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (double)(random.NextDouble()); _data2[i] = (double)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Double>, byte>(ref _fld1), ref Unsafe.As<Double, byte>(ref _data1[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Double>, byte>(ref _fld2), ref Unsafe.As<Double, byte>(ref _data2[0]), VectorSize); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (double)(random.NextDouble()); _data2[i] = (double)(random.NextDouble()); } + _dataTable = new SimpleBinaryOpTest__DataTable<Double>(_data1, _data2, new Double[ElementCount], VectorSize); + } + + public bool IsSupported => Sse2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse2.CompareOrdered( + Unsafe.Read<Vector128<Double>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<Double>>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse2.CompareOrdered( + Sse2.LoadVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Double*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse2.CompareOrdered( + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.CompareOrdered), new Type[] { typeof(Vector128<Double>), typeof(Vector128<Double>) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector128<Double>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<Double>>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Double>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.CompareOrdered), new Type[] { typeof(Vector128<Double>), typeof(Vector128<Double>) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Double*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Double>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.CompareOrdered), new Type[] { typeof(Vector128<Double>), typeof(Vector128<Double>) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Double>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse2.CompareOrdered( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read<Vector128<Double>>(_dataTable.inArray1Ptr); + var right = Unsafe.Read<Vector128<Double>>(_dataTable.inArray2Ptr); + var result = Sse2.CompareOrdered(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((Double*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((Double*)(_dataTable.inArray2Ptr)); + var result = Sse2.CompareOrdered(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray2Ptr)); + var result = Sse2.CompareOrdered(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__CompareOrderedDouble(); + var result = Sse2.CompareOrdered(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse2.CompareOrdered(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128<Double> left, Vector128<Double> right, void* result, [CallerMemberName] string method = "") + { + Double[] inArray1 = new Double[ElementCount]; + Double[] inArray2 = new Double[ElementCount]; + Double[] outArray = new Double[ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Double[] inArray1 = new Double[ElementCount]; + Double[] inArray2 = new Double[ElementCount]; + Double[] outArray = new Double[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Double[] left, Double[] right, Double[] result, [CallerMemberName] string method = "") + { + if (BitConverter.DoubleToInt64Bits(result[0]) != ((!double.IsNaN(left[0]) && !double.IsNaN(right[0])) ? -1 : 0)) + { + Succeeded = false; + } + else + { + for (var i = 1; i < left.Length; i++) + { + if (BitConverter.DoubleToInt64Bits(result[i]) != ((!double.IsNaN(left[i]) && !double.IsNaN(right[i])) ? -1 : 0)) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Sse2)}.{nameof(Sse2.CompareOrdered)}<Double>: {method} failed:"); + Console.WriteLine($" left: ({string.Join(", ", left)})"); + Console.WriteLine($" right: ({string.Join(", ", right)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareOrdered.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareOrdered.cs deleted file mode 100644 index 03f9ee69d8..0000000000 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareOrdered.cs +++ /dev/null @@ -1,62 +0,0 @@ -// 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. -// - -using System; -using System.Runtime.Intrinsics; -using System.Runtime.Intrinsics.X86; - -namespace IntelHardwareIntrinsicTest -{ - internal static partial class Program - { - private const int Pass = 100; - private const int Fail = 0; - - static unsafe int Main(string[] args) - { - int testResult = Pass; - int testsCount = 21; - string methodUnderTestName = nameof(Sse2.CompareOrdered); - - if (Sse2.IsSupported) - { - using (var doubleTable = TestTableSse2<double>.Create(testsCount)) - { - for (int i = 0; i < testsCount; i++) - { - (Vector128<double>, Vector128<double>, Vector128<double>) value = doubleTable[i]; - var result = Sse2.CompareOrdered(value.Item1, value.Item2); - doubleTable.SetOutArray(result); - } - - CheckMethod<double> checkDouble = (double x, double y, double z, ref double a) => - { - if (!double.IsNaN(x) && !double.IsNaN(y)) - { - a = BitConverter.Int64BitsToDouble(-1); - } - else - { - a = 0; - } - return BitConverter.DoubleToInt64Bits(a) == BitConverter.DoubleToInt64Bits(z); - }; - - if (!doubleTable.CheckResult(checkDouble)) - { - PrintError(doubleTable, methodUnderTestName, "(x, y, z, ref a) => (a = (!double.IsNaN(x) && !double.IsNaN(y)) ? double.NaN : 0) == z", checkDouble); - testResult = Fail; - } - } - } - else - { - Console.WriteLine($"Sse2.IsSupported: {Sse2.IsSupported}, skipped tests of {typeof(Sse2)}.{methodUnderTestName}"); - } - - return testResult; - } - } -} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareOrdered_r.csproj b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareOrdered_r.csproj deleted file mode 100644 index 1f76671f06..0000000000 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareOrdered_r.csproj +++ /dev/null @@ -1,38 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" /> - <PropertyGroup> - <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> - <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> - <SchemaVersion>2.0</SchemaVersion> - <ProjectGuid>{2099478C-8A85-4032-8F86-402DA54F8FA2}</ProjectGuid> - <OutputType>Exe</OutputType> - <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> - <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir> - <AllowUnsafeBlocks>true</AllowUnsafeBlocks> - </PropertyGroup> - <!-- Default configurations to help VS understand the configurations --> - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> - </PropertyGroup> - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' " /> - <ItemGroup> - <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies"> - <Visible>False</Visible> - </CodeAnalysisDependentAssemblyPaths> - </ItemGroup> - <PropertyGroup> - <DebugType>None</DebugType> - <Optimize> - </Optimize> - </PropertyGroup> - <ItemGroup> - <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" /> - </ItemGroup> - <ItemGroup> - <Compile Include="CompareOrdered.cs" /> - <Compile Include="TestTableSse2.cs" /> - </ItemGroup> - <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" /> - <PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' "> - </PropertyGroup> -</Project>
\ No newline at end of file diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareOrdered_ro.csproj b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareOrdered_ro.csproj deleted file mode 100644 index 9e9d5c5d4b..0000000000 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareOrdered_ro.csproj +++ /dev/null @@ -1,37 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" /> - <PropertyGroup> - <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> - <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> - <SchemaVersion>2.0</SchemaVersion> - <ProjectGuid>{AA7AFEBE-8C40-4A22-8A1E-5FC39EDD9A51}</ProjectGuid> - <OutputType>Exe</OutputType> - <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> - <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir> - <AllowUnsafeBlocks>true</AllowUnsafeBlocks> - </PropertyGroup> - <!-- Default configurations to help VS understand the configurations --> - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> - </PropertyGroup> - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' " /> - <ItemGroup> - <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies"> - <Visible>False</Visible> - </CodeAnalysisDependentAssemblyPaths> - </ItemGroup> - <PropertyGroup> - <DebugType>None</DebugType> - <Optimize>True</Optimize> - </PropertyGroup> - <ItemGroup> - <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" /> - </ItemGroup> - <ItemGroup> - <Compile Include="CompareOrdered.cs" /> - <Compile Include="TestTableSse2.cs" /> - </ItemGroup> - <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" /> - <PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' "> - </PropertyGroup> -</Project> diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareUnordered.Double.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareUnordered.Double.cs new file mode 100644 index 0000000000..a213bb723c --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareUnordered.Double.cs @@ -0,0 +1,315 @@ +// 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 CompareUnorderedDouble() + { + var test = new SimpleBinaryOpTest__CompareUnorderedDouble(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + // 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(); + + // 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(); + + // 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 works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + 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__CompareUnorderedDouble + { + private const int VectorSize = 16; + private const int ElementCount = VectorSize / sizeof(Double); + + private static Double[] _data1 = new Double[ElementCount]; + private static Double[] _data2 = new Double[ElementCount]; + + private static Vector128<Double> _clsVar1; + private static Vector128<Double> _clsVar2; + + private Vector128<Double> _fld1; + private Vector128<Double> _fld2; + + private SimpleBinaryOpTest__DataTable<Double> _dataTable; + + static SimpleBinaryOpTest__CompareUnorderedDouble() + { + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (double)(random.NextDouble()); _data2[i] = (double)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Double>, byte>(ref _clsVar1), ref Unsafe.As<Double, byte>(ref _data2[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Double>, byte>(ref _clsVar2), ref Unsafe.As<Double, byte>(ref _data1[0]), VectorSize); + } + + public SimpleBinaryOpTest__CompareUnorderedDouble() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (double)(random.NextDouble()); _data2[i] = (double)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Double>, byte>(ref _fld1), ref Unsafe.As<Double, byte>(ref _data1[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Double>, byte>(ref _fld2), ref Unsafe.As<Double, byte>(ref _data2[0]), VectorSize); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (double)(random.NextDouble()); _data2[i] = (double)(random.NextDouble()); } + _dataTable = new SimpleBinaryOpTest__DataTable<Double>(_data1, _data2, new Double[ElementCount], VectorSize); + } + + public bool IsSupported => Sse2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse2.CompareUnordered( + Unsafe.Read<Vector128<Double>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<Double>>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse2.CompareUnordered( + Sse2.LoadVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Double*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse2.CompareUnordered( + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.CompareUnordered), new Type[] { typeof(Vector128<Double>), typeof(Vector128<Double>) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector128<Double>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<Double>>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Double>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.CompareUnordered), new Type[] { typeof(Vector128<Double>), typeof(Vector128<Double>) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Double*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Double>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.CompareUnordered), new Type[] { typeof(Vector128<Double>), typeof(Vector128<Double>) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Double>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse2.CompareUnordered( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read<Vector128<Double>>(_dataTable.inArray1Ptr); + var right = Unsafe.Read<Vector128<Double>>(_dataTable.inArray2Ptr); + var result = Sse2.CompareUnordered(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((Double*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((Double*)(_dataTable.inArray2Ptr)); + var result = Sse2.CompareUnordered(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray2Ptr)); + var result = Sse2.CompareUnordered(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__CompareUnorderedDouble(); + var result = Sse2.CompareUnordered(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse2.CompareUnordered(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128<Double> left, Vector128<Double> right, void* result, [CallerMemberName] string method = "") + { + Double[] inArray1 = new Double[ElementCount]; + Double[] inArray2 = new Double[ElementCount]; + Double[] outArray = new Double[ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Double[] inArray1 = new Double[ElementCount]; + Double[] inArray2 = new Double[ElementCount]; + Double[] outArray = new Double[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Double[] left, Double[] right, Double[] result, [CallerMemberName] string method = "") + { + if (BitConverter.DoubleToInt64Bits(result[0]) != ((double.IsNaN(left[0]) || double.IsNaN(right[0])) ? -1 : 0)) + { + Succeeded = false; + } + else + { + for (var i = 1; i < left.Length; i++) + { + if (BitConverter.DoubleToInt64Bits(result[i]) != ((double.IsNaN(left[i]) || double.IsNaN(right[i])) ? -1 : 0)) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Sse2)}.{nameof(Sse2.CompareUnordered)}<Double>: {method} failed:"); + Console.WriteLine($" left: ({string.Join(", ", left)})"); + Console.WriteLine($" right: ({string.Join(", ", right)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareUnordered.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareUnordered.cs deleted file mode 100644 index 036aac646d..0000000000 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareUnordered.cs +++ /dev/null @@ -1,62 +0,0 @@ -// 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. -// - -using System; -using System.Runtime.Intrinsics; -using System.Runtime.Intrinsics.X86; - -namespace IntelHardwareIntrinsicTest -{ - internal static partial class Program - { - private const int Pass = 100; - private const int Fail = 0; - - static unsafe int Main(string[] args) - { - int testResult = Pass; - int testsCount = 21; - string methodUnderTestName = nameof(Sse2.CompareUnordered); - - if (Sse2.IsSupported) - { - using (var doubleTable = TestTableSse2<double>.Create(testsCount)) - { - for (int i = 0; i < testsCount; i++) - { - (Vector128<double>, Vector128<double>, Vector128<double>) value = doubleTable[i]; - var result = Sse2.CompareUnordered(value.Item1, value.Item2); - doubleTable.SetOutArray(result); - } - - CheckMethod<double> checkDouble = (double x, double y, double z, ref double a) => - { - if (double.IsNaN(x) || double.IsNaN(y)) - { - a = BitConverter.Int64BitsToDouble(-1); - } - else - { - a = 0; - } - return BitConverter.DoubleToInt64Bits(a) == BitConverter.DoubleToInt64Bits(z); - }; - - if (!doubleTable.CheckResult(checkDouble)) - { - PrintError(doubleTable, methodUnderTestName, "(x, y, z, ref a) => (a = (double.IsNaN(x) || double.IsNaN(y)) ? double.NaN : 0) == z", checkDouble); - testResult = Fail; - } - } - } - else - { - Console.WriteLine($"Sse2.IsSupported: {Sse2.IsSupported}, skipped tests of {typeof(Sse2)}.{methodUnderTestName}"); - } - - return testResult; - } - } -} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareUnordered_r.csproj b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareUnordered_r.csproj deleted file mode 100644 index 94f475da87..0000000000 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareUnordered_r.csproj +++ /dev/null @@ -1,38 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" /> - <PropertyGroup> - <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> - <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> - <SchemaVersion>2.0</SchemaVersion> - <ProjectGuid>{15931119-A410-40C5-9FCC-D7A714C68512}</ProjectGuid> - <OutputType>Exe</OutputType> - <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> - <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir> - <AllowUnsafeBlocks>true</AllowUnsafeBlocks> - </PropertyGroup> - <!-- Default configurations to help VS understand the configurations --> - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> - </PropertyGroup> - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' " /> - <ItemGroup> - <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies"> - <Visible>False</Visible> - </CodeAnalysisDependentAssemblyPaths> - </ItemGroup> - <PropertyGroup> - <DebugType>None</DebugType> - <Optimize> - </Optimize> - </PropertyGroup> - <ItemGroup> - <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" /> - </ItemGroup> - <ItemGroup> - <Compile Include="CompareUnordered.cs" /> - <Compile Include="TestTableSse2.cs" /> - </ItemGroup> - <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" /> - <PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' "> - </PropertyGroup> -</Project>
\ No newline at end of file diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareUnordered_ro.csproj b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareUnordered_ro.csproj deleted file mode 100644 index a994bc71c8..0000000000 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/CompareUnordered_ro.csproj +++ /dev/null @@ -1,37 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" /> - <PropertyGroup> - <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> - <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> - <SchemaVersion>2.0</SchemaVersion> - <ProjectGuid>{66739F14-FEA4-4993-B0E7-3E9B0D824FED}</ProjectGuid> - <OutputType>Exe</OutputType> - <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> - <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir> - <AllowUnsafeBlocks>true</AllowUnsafeBlocks> - </PropertyGroup> - <!-- Default configurations to help VS understand the configurations --> - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> - </PropertyGroup> - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' " /> - <ItemGroup> - <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies"> - <Visible>False</Visible> - </CodeAnalysisDependentAssemblyPaths> - </ItemGroup> - <PropertyGroup> - <DebugType>None</DebugType> - <Optimize>True</Optimize> - </PropertyGroup> - <ItemGroup> - <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" /> - </ItemGroup> - <ItemGroup> - <Compile Include="CompareUnordered.cs" /> - <Compile Include="TestTableSse2.cs" /> - </ItemGroup> - <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" /> - <PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' "> - </PropertyGroup> -</Project>
\ No newline at end of file diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Divide.Double.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Divide.Double.cs new file mode 100644 index 0000000000..34315c1f5b --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Divide.Double.cs @@ -0,0 +1,315 @@ +// 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 DivideDouble() + { + var test = new SimpleBinaryOpTest__DivideDouble(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + // 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(); + + // 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(); + + // 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 works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + 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__DivideDouble + { + private const int VectorSize = 16; + private const int ElementCount = VectorSize / sizeof(Double); + + private static Double[] _data1 = new Double[ElementCount]; + private static Double[] _data2 = new Double[ElementCount]; + + private static Vector128<Double> _clsVar1; + private static Vector128<Double> _clsVar2; + + private Vector128<Double> _fld1; + private Vector128<Double> _fld2; + + private SimpleBinaryOpTest__DataTable<Double> _dataTable; + + static SimpleBinaryOpTest__DivideDouble() + { + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (double)(random.NextDouble()); _data2[i] = (double)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Double>, byte>(ref _clsVar1), ref Unsafe.As<Double, byte>(ref _data2[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Double>, byte>(ref _clsVar2), ref Unsafe.As<Double, byte>(ref _data1[0]), VectorSize); + } + + public SimpleBinaryOpTest__DivideDouble() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (double)(random.NextDouble()); _data2[i] = (double)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Double>, byte>(ref _fld1), ref Unsafe.As<Double, byte>(ref _data1[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Double>, byte>(ref _fld2), ref Unsafe.As<Double, byte>(ref _data2[0]), VectorSize); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (double)(random.NextDouble()); _data2[i] = (double)(random.NextDouble()); } + _dataTable = new SimpleBinaryOpTest__DataTable<Double>(_data1, _data2, new Double[ElementCount], VectorSize); + } + + public bool IsSupported => Sse2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse2.Divide( + Unsafe.Read<Vector128<Double>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<Double>>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse2.Divide( + Sse2.LoadVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Double*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse2.Divide( + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Divide), new Type[] { typeof(Vector128<Double>), typeof(Vector128<Double>) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector128<Double>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<Double>>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Double>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Divide), new Type[] { typeof(Vector128<Double>), typeof(Vector128<Double>) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Double*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Double>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Divide), new Type[] { typeof(Vector128<Double>), typeof(Vector128<Double>) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Double>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse2.Divide( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read<Vector128<Double>>(_dataTable.inArray1Ptr); + var right = Unsafe.Read<Vector128<Double>>(_dataTable.inArray2Ptr); + var result = Sse2.Divide(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((Double*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((Double*)(_dataTable.inArray2Ptr)); + var result = Sse2.Divide(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray2Ptr)); + var result = Sse2.Divide(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__DivideDouble(); + var result = Sse2.Divide(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse2.Divide(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128<Double> left, Vector128<Double> right, void* result, [CallerMemberName] string method = "") + { + Double[] inArray1 = new Double[ElementCount]; + Double[] inArray2 = new Double[ElementCount]; + Double[] outArray = new Double[ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Double[] inArray1 = new Double[ElementCount]; + Double[] inArray2 = new Double[ElementCount]; + Double[] outArray = new Double[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Double[] left, Double[] right, Double[] result, [CallerMemberName] string method = "") + { + if (BitConverter.DoubleToInt64Bits(left[0] / right[0]) != BitConverter.DoubleToInt64Bits(result[0])) + { + Succeeded = false; + } + else + { + for (var i = 1; i < left.Length; i++) + { + if (BitConverter.DoubleToInt64Bits(left[i] / right[i]) != BitConverter.DoubleToInt64Bits(result[i])) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Sse2)}.{nameof(Sse2.Divide)}<Double>: {method} failed:"); + Console.WriteLine($" left: ({string.Join(", ", left)})"); + Console.WriteLine($" right: ({string.Join(", ", right)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Divide.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Divide.cs deleted file mode 100644 index 764277a5c2..0000000000 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Divide.cs +++ /dev/null @@ -1,51 +0,0 @@ -// 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. -// - -using System; -using System.Runtime.Intrinsics; -using System.Runtime.Intrinsics.X86; - -namespace IntelHardwareIntrinsicTest -{ - internal static partial class Program - { - private const int Pass = 100; - private const int Fail = 0; - - static unsafe int Main(string[] args) - { - int testResult = Pass; - int testsCount = 21; - string methodUnderTestName = nameof(Sse2.Divide); - - if (Sse2.IsSupported) - { - using (var doubleTable = TestTableSse2<double>.Create(testsCount)) - { - for (int i = 0; i < testsCount; i++) - { - (Vector128<double>, Vector128<double>, Vector128<double>) value = doubleTable[i]; - var result = Sse2.Divide(value.Item1, value.Item2); - doubleTable.SetOutArray(result); - } - - CheckMethod<double> checkDouble = (double x, double y, double z, ref double a) => (a = x / y) == z; - - if (!doubleTable.CheckResult(checkDouble)) - { - PrintError(doubleTable, methodUnderTestName, "(double x, double y, double z, ref double a) => (a = x / y) == z", checkDouble); - testResult = Fail; - } - } - } - else - { - Console.WriteLine($"Sse2.IsSupported: {Sse2.IsSupported}, skipped tests of {typeof(Sse2)}.{methodUnderTestName}"); - } - - return testResult; - } - } -} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Divide_r.csproj b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Divide_r.csproj deleted file mode 100644 index 397815001b..0000000000 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Divide_r.csproj +++ /dev/null @@ -1,38 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" /> - <PropertyGroup> - <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> - <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> - <SchemaVersion>2.0</SchemaVersion> - <ProjectGuid>{87A3726E-381D-417E-B498-3C4FFB632544}</ProjectGuid> - <OutputType>Exe</OutputType> - <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> - <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir> - <AllowUnsafeBlocks>true</AllowUnsafeBlocks> - </PropertyGroup> - <!-- Default configurations to help VS understand the configurations --> - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> - </PropertyGroup> - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' " /> - <ItemGroup> - <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies"> - <Visible>False</Visible> - </CodeAnalysisDependentAssemblyPaths> - </ItemGroup> - <PropertyGroup> - <DebugType>None</DebugType> - <Optimize> - </Optimize> - </PropertyGroup> - <ItemGroup> - <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" /> - </ItemGroup> - <ItemGroup> - <Compile Include="Divide.cs" /> - <Compile Include="TestTableSse2.cs" /> - </ItemGroup> - <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" /> - <PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' "> - </PropertyGroup> -</Project>
\ No newline at end of file diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Divide_ro.csproj b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Divide_ro.csproj deleted file mode 100644 index eeacfa2d6e..0000000000 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Divide_ro.csproj +++ /dev/null @@ -1,37 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" /> - <PropertyGroup> - <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> - <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> - <SchemaVersion>2.0</SchemaVersion> - <ProjectGuid>{8AABA105-3887-4CA6-83F9-3CD59DAAC7E8}</ProjectGuid> - <OutputType>Exe</OutputType> - <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> - <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir> - <AllowUnsafeBlocks>true</AllowUnsafeBlocks> - </PropertyGroup> - <!-- Default configurations to help VS understand the configurations --> - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> - </PropertyGroup> - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' " /> - <ItemGroup> - <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies"> - <Visible>False</Visible> - </CodeAnalysisDependentAssemblyPaths> - </ItemGroup> - <PropertyGroup> - <DebugType>None</DebugType> - <Optimize>True</Optimize> - </PropertyGroup> - <ItemGroup> - <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" /> - </ItemGroup> - <ItemGroup> - <Compile Include="Divide.cs" /> - <Compile Include="TestTableSse2.cs" /> - </ItemGroup> - <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" /> - <PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' "> - </PropertyGroup> -</Project>
\ No newline at end of file diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Max.Byte.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Max.Byte.cs new file mode 100644 index 0000000000..d03267468f --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Max.Byte.cs @@ -0,0 +1,315 @@ +// 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 MaxByte() + { + var test = new SimpleBinaryOpTest__MaxByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + // 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(); + + // 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(); + + // 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 works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + 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__MaxByte + { + private const int VectorSize = 16; + private const int ElementCount = VectorSize / sizeof(Byte); + + private static Byte[] _data1 = new Byte[ElementCount]; + private static Byte[] _data2 = new Byte[ElementCount]; + + private static Vector128<Byte> _clsVar1; + private static Vector128<Byte> _clsVar2; + + private Vector128<Byte> _fld1; + private Vector128<Byte> _fld2; + + private SimpleBinaryOpTest__DataTable<Byte> _dataTable; + + static SimpleBinaryOpTest__MaxByte() + { + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (byte)(random.Next(0, byte.MaxValue)); _data2[i] = (byte)(random.Next(0, byte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Byte>, byte>(ref _clsVar1), ref Unsafe.As<Byte, byte>(ref _data2[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Byte>, byte>(ref _clsVar2), ref Unsafe.As<Byte, byte>(ref _data1[0]), VectorSize); + } + + public SimpleBinaryOpTest__MaxByte() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (byte)(random.Next(0, byte.MaxValue)); _data2[i] = (byte)(random.Next(0, byte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Byte>, byte>(ref _fld1), ref Unsafe.As<Byte, byte>(ref _data1[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Byte>, byte>(ref _fld2), ref Unsafe.As<Byte, byte>(ref _data2[0]), VectorSize); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (byte)(random.Next(0, byte.MaxValue)); _data2[i] = (byte)(random.Next(0, byte.MaxValue)); } + _dataTable = new SimpleBinaryOpTest__DataTable<Byte>(_data1, _data2, new Byte[ElementCount], VectorSize); + } + + public bool IsSupported => Sse2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse2.Max( + Unsafe.Read<Vector128<Byte>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<Byte>>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse2.Max( + Sse2.LoadVector128((Byte*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Byte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse2.Max( + Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Max), new Type[] { typeof(Vector128<Byte>), typeof(Vector128<Byte>) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector128<Byte>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<Byte>>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Byte>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Max), new Type[] { typeof(Vector128<Byte>), typeof(Vector128<Byte>) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Byte*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Byte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Byte>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Max), new Type[] { typeof(Vector128<Byte>), typeof(Vector128<Byte>) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Byte>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse2.Max( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read<Vector128<Byte>>(_dataTable.inArray1Ptr); + var right = Unsafe.Read<Vector128<Byte>>(_dataTable.inArray2Ptr); + var result = Sse2.Max(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((Byte*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((Byte*)(_dataTable.inArray2Ptr)); + var result = Sse2.Max(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray2Ptr)); + var result = Sse2.Max(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__MaxByte(); + var result = Sse2.Max(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse2.Max(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128<Byte> left, Vector128<Byte> right, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[ElementCount]; + Byte[] inArray2 = new Byte[ElementCount]; + Byte[] outArray = new Byte[ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Byte, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[ElementCount]; + Byte[] inArray2 = new Byte[ElementCount]; + Byte[] outArray = new Byte[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Byte, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Byte, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Byte, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Byte[] left, Byte[] right, Byte[] result, [CallerMemberName] string method = "") + { + if (Math.Max(left[0], right[0]) != result[0]) + { + Succeeded = false; + } + else + { + for (var i = 1; i < left.Length; i++) + { + if (Math.Max(left[i], right[i]) != result[i]) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Sse2)}.{nameof(Sse2.Max)}<Byte>: {method} failed:"); + Console.WriteLine($" left: ({string.Join(", ", left)})"); + Console.WriteLine($" right: ({string.Join(", ", right)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Max.Double.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Max.Double.cs new file mode 100644 index 0000000000..49df538161 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Max.Double.cs @@ -0,0 +1,315 @@ +// 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 MaxDouble() + { + var test = new SimpleBinaryOpTest__MaxDouble(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + // 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(); + + // 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(); + + // 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 works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + 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__MaxDouble + { + private const int VectorSize = 16; + private const int ElementCount = VectorSize / sizeof(Double); + + private static Double[] _data1 = new Double[ElementCount]; + private static Double[] _data2 = new Double[ElementCount]; + + private static Vector128<Double> _clsVar1; + private static Vector128<Double> _clsVar2; + + private Vector128<Double> _fld1; + private Vector128<Double> _fld2; + + private SimpleBinaryOpTest__DataTable<Double> _dataTable; + + static SimpleBinaryOpTest__MaxDouble() + { + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (double)(random.NextDouble()); _data2[i] = (double)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Double>, byte>(ref _clsVar1), ref Unsafe.As<Double, byte>(ref _data2[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Double>, byte>(ref _clsVar2), ref Unsafe.As<Double, byte>(ref _data1[0]), VectorSize); + } + + public SimpleBinaryOpTest__MaxDouble() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (double)(random.NextDouble()); _data2[i] = (double)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Double>, byte>(ref _fld1), ref Unsafe.As<Double, byte>(ref _data1[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Double>, byte>(ref _fld2), ref Unsafe.As<Double, byte>(ref _data2[0]), VectorSize); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (double)(random.NextDouble()); _data2[i] = (double)(random.NextDouble()); } + _dataTable = new SimpleBinaryOpTest__DataTable<Double>(_data1, _data2, new Double[ElementCount], VectorSize); + } + + public bool IsSupported => Sse2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse2.Max( + Unsafe.Read<Vector128<Double>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<Double>>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse2.Max( + Sse2.LoadVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Double*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse2.Max( + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Max), new Type[] { typeof(Vector128<Double>), typeof(Vector128<Double>) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector128<Double>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<Double>>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Double>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Max), new Type[] { typeof(Vector128<Double>), typeof(Vector128<Double>) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Double*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Double>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Max), new Type[] { typeof(Vector128<Double>), typeof(Vector128<Double>) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Double>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse2.Max( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read<Vector128<Double>>(_dataTable.inArray1Ptr); + var right = Unsafe.Read<Vector128<Double>>(_dataTable.inArray2Ptr); + var result = Sse2.Max(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((Double*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((Double*)(_dataTable.inArray2Ptr)); + var result = Sse2.Max(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray2Ptr)); + var result = Sse2.Max(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__MaxDouble(); + var result = Sse2.Max(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse2.Max(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128<Double> left, Vector128<Double> right, void* result, [CallerMemberName] string method = "") + { + Double[] inArray1 = new Double[ElementCount]; + Double[] inArray2 = new Double[ElementCount]; + Double[] outArray = new Double[ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Double[] inArray1 = new Double[ElementCount]; + Double[] inArray2 = new Double[ElementCount]; + Double[] outArray = new Double[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Double[] left, Double[] right, Double[] result, [CallerMemberName] string method = "") + { + if (BitConverter.DoubleToInt64Bits(Math.Max(left[0], right[0])) != BitConverter.DoubleToInt64Bits(result[0])) + { + Succeeded = false; + } + else + { + for (var i = 1; i < left.Length; i++) + { + if (BitConverter.DoubleToInt64Bits(Math.Max(left[i], right[i])) != BitConverter.DoubleToInt64Bits(result[i])) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Sse2)}.{nameof(Sse2.Max)}<Double>: {method} failed:"); + Console.WriteLine($" left: ({string.Join(", ", left)})"); + Console.WriteLine($" right: ({string.Join(", ", right)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Max.Int16.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Max.Int16.cs new file mode 100644 index 0000000000..20b2d6fe26 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Max.Int16.cs @@ -0,0 +1,315 @@ +// 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 MaxInt16() + { + var test = new SimpleBinaryOpTest__MaxInt16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + // 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(); + + // 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(); + + // 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 works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + 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__MaxInt16 + { + private const int VectorSize = 16; + private const int ElementCount = VectorSize / sizeof(Int16); + + private static Int16[] _data1 = new Int16[ElementCount]; + private static Int16[] _data2 = new Int16[ElementCount]; + + private static Vector128<Int16> _clsVar1; + private static Vector128<Int16> _clsVar2; + + private Vector128<Int16> _fld1; + private Vector128<Int16> _fld2; + + private SimpleBinaryOpTest__DataTable<Int16> _dataTable; + + static SimpleBinaryOpTest__MaxInt16() + { + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (short)(random.Next(short.MinValue, short.MaxValue)); _data2[i] = (short)(random.Next(short.MinValue, short.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int16>, byte>(ref _clsVar1), ref Unsafe.As<Int16, byte>(ref _data2[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int16>, byte>(ref _clsVar2), ref Unsafe.As<Int16, byte>(ref _data1[0]), VectorSize); + } + + public SimpleBinaryOpTest__MaxInt16() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (short)(random.Next(short.MinValue, short.MaxValue)); _data2[i] = (short)(random.Next(short.MinValue, short.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int16>, byte>(ref _fld1), ref Unsafe.As<Int16, byte>(ref _data1[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int16>, byte>(ref _fld2), ref Unsafe.As<Int16, byte>(ref _data2[0]), VectorSize); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (short)(random.Next(short.MinValue, short.MaxValue)); _data2[i] = (short)(random.Next(short.MinValue, short.MaxValue)); } + _dataTable = new SimpleBinaryOpTest__DataTable<Int16>(_data1, _data2, new Int16[ElementCount], VectorSize); + } + + public bool IsSupported => Sse2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse2.Max( + Unsafe.Read<Vector128<Int16>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<Int16>>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse2.Max( + Sse2.LoadVector128((Int16*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Int16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse2.Max( + Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Max), new Type[] { typeof(Vector128<Int16>), typeof(Vector128<Int16>) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector128<Int16>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<Int16>>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Int16>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Max), new Type[] { typeof(Vector128<Int16>), typeof(Vector128<Int16>) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Int16*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Int16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Int16>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Max), new Type[] { typeof(Vector128<Int16>), typeof(Vector128<Int16>) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Int16>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse2.Max( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read<Vector128<Int16>>(_dataTable.inArray1Ptr); + var right = Unsafe.Read<Vector128<Int16>>(_dataTable.inArray2Ptr); + var result = Sse2.Max(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((Int16*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((Int16*)(_dataTable.inArray2Ptr)); + var result = Sse2.Max(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray2Ptr)); + var result = Sse2.Max(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__MaxInt16(); + var result = Sse2.Max(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse2.Max(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128<Int16> left, Vector128<Int16> right, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[ElementCount]; + Int16[] inArray2 = new Int16[ElementCount]; + Int16[] outArray = new Int16[ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int16, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[ElementCount]; + Int16[] inArray2 = new Int16[ElementCount]; + Int16[] outArray = new Int16[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int16, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int16, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int16, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int16[] left, Int16[] right, Int16[] result, [CallerMemberName] string method = "") + { + if (Math.Max(left[0], right[0]) != result[0]) + { + Succeeded = false; + } + else + { + for (var i = 1; i < left.Length; i++) + { + if (Math.Max(left[i], right[i]) != result[i]) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Sse2)}.{nameof(Sse2.Max)}<Int16>: {method} failed:"); + Console.WriteLine($" left: ({string.Join(", ", left)})"); + Console.WriteLine($" right: ({string.Join(", ", right)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Max.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Max.cs deleted file mode 100644 index 996c1b525a..0000000000 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Max.cs +++ /dev/null @@ -1,83 +0,0 @@ -// 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. -// - -using System; -using System.Runtime.Intrinsics; -using System.Runtime.Intrinsics.X86; - -namespace IntelHardwareIntrinsicTest -{ - internal static partial class Program - { - const int Pass = 100; - const int Fail = 0; - - static unsafe int Main(string[] args) - { - int testResult = Pass; - int testsCount = 21; - string methodUnderTestName = nameof(Sse2.Max); - - if (Sse2.IsSupported) - { - using (var doubleTable = TestTableSse2<double>.Create(testsCount)) - using (var shortTable = TestTableSse2<short>.Create(testsCount)) - using (var byteTable = TestTableSse2<byte>.Create(testsCount)) - { - for (int i = 0; i < testsCount; i++) - { - (Vector128<double>, Vector128<double>, Vector128<double>) value = doubleTable[i]; - var result = Sse2.Max(value.Item1, value.Item2); - doubleTable.SetOutArray(result); - } - - for (int i = 0; i < testsCount; i++) - { - (Vector128<short>, Vector128<short>, Vector128<short>) value = shortTable[i]; - var result = Sse2.Max(value.Item1, value.Item2); - shortTable.SetOutArray(result); - } - - for (int i = 0; i < testsCount; i++) - { - (Vector128<byte>, Vector128<byte>, Vector128<byte>) value = byteTable[i]; - var result = Sse2.Max(value.Item1, value.Item2); - byteTable.SetOutArray(result); - } - - CheckMethod<double> checkDouble = (double x, double y, double z, ref double a) => (a = x > y ? x : y) == z; - - if (!doubleTable.CheckResult(checkDouble)) - { - PrintError(doubleTable, methodUnderTestName, "(double x, double y, double z, ref double a) => (a = x > y ? x : y) == z", checkDouble); - testResult = Fail; - } - - CheckMethod<short> checkInt16 = (short x, short y, short z, ref short a) => (a = x > y ? x : y) == z; - - if (!shortTable.CheckResult(checkInt16)) - { - PrintError(shortTable, methodUnderTestName, "(short x, short y, short z, ref short a) => (a = x > y ? x : y) == z", checkInt16); - testResult = Fail; - } - - CheckMethod<byte> checkByte = (byte x, byte y, byte z, ref byte a) => (a = x > y ? x : y) == z; - - if (!byteTable.CheckResult(checkByte)) - { - PrintError(byteTable, methodUnderTestName, "(byte x, byte y, byte z, ref byte a) => (a = x > y ? x : y) == z", checkByte); - testResult = Fail; - } - } - } - else - { - Console.WriteLine($"Sse2.IsSupported: {Sse2.IsSupported}, skipped tests of {typeof(Sse2)}.{methodUnderTestName}"); - } - - return testResult; - } - } -} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Max_r.csproj b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Max_r.csproj deleted file mode 100644 index 756e49a858..0000000000 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Max_r.csproj +++ /dev/null @@ -1,38 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" /> - <PropertyGroup> - <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> - <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> - <SchemaVersion>2.0</SchemaVersion> - <ProjectGuid>{E47ED2C4-6A89-43E3-AD1A-8FEDA7D8FA03}</ProjectGuid> - <OutputType>Exe</OutputType> - <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> - <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir> - <AllowUnsafeBlocks>true</AllowUnsafeBlocks> - </PropertyGroup> - <!-- Default configurations to help VS understand the configurations --> - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> - </PropertyGroup> - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' " /> - <ItemGroup> - <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies"> - <Visible>False</Visible> - </CodeAnalysisDependentAssemblyPaths> - </ItemGroup> - <PropertyGroup> - <DebugType>None</DebugType> - <Optimize> - </Optimize> - </PropertyGroup> - <ItemGroup> - <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" /> - </ItemGroup> - <ItemGroup> - <Compile Include="Max.cs" /> - <Compile Include="TestTableSse2.cs" /> - </ItemGroup> - <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" /> - <PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' "> - </PropertyGroup> -</Project>
\ No newline at end of file diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Max_ro.csproj b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Max_ro.csproj deleted file mode 100644 index aa9defa8a8..0000000000 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Max_ro.csproj +++ /dev/null @@ -1,37 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" /> - <PropertyGroup> - <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> - <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> - <SchemaVersion>2.0</SchemaVersion> - <ProjectGuid>{75455928-80BB-4905-956F-0D53BFC4D804}</ProjectGuid> - <OutputType>Exe</OutputType> - <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> - <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir> - <AllowUnsafeBlocks>true</AllowUnsafeBlocks> - </PropertyGroup> - <!-- Default configurations to help VS understand the configurations --> - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> - </PropertyGroup> - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' " /> - <ItemGroup> - <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies"> - <Visible>False</Visible> - </CodeAnalysisDependentAssemblyPaths> - </ItemGroup> - <PropertyGroup> - <DebugType>None</DebugType> - <Optimize>True</Optimize> - </PropertyGroup> - <ItemGroup> - <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" /> - </ItemGroup> - <ItemGroup> - <Compile Include="Max.cs" /> - <Compile Include="TestTableSse2.cs" /> - </ItemGroup> - <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" /> - <PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' "> - </PropertyGroup> -</Project>
\ No newline at end of file diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Min.Byte.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Min.Byte.cs new file mode 100644 index 0000000000..73a6b915e8 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Min.Byte.cs @@ -0,0 +1,315 @@ +// 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 MinByte() + { + var test = new SimpleBinaryOpTest__MinByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + // 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(); + + // 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(); + + // 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 works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + 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__MinByte + { + private const int VectorSize = 16; + private const int ElementCount = VectorSize / sizeof(Byte); + + private static Byte[] _data1 = new Byte[ElementCount]; + private static Byte[] _data2 = new Byte[ElementCount]; + + private static Vector128<Byte> _clsVar1; + private static Vector128<Byte> _clsVar2; + + private Vector128<Byte> _fld1; + private Vector128<Byte> _fld2; + + private SimpleBinaryOpTest__DataTable<Byte> _dataTable; + + static SimpleBinaryOpTest__MinByte() + { + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (byte)(random.Next(0, byte.MinValue)); _data2[i] = (byte)(random.Next(0, byte.MinValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Byte>, byte>(ref _clsVar1), ref Unsafe.As<Byte, byte>(ref _data2[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Byte>, byte>(ref _clsVar2), ref Unsafe.As<Byte, byte>(ref _data1[0]), VectorSize); + } + + public SimpleBinaryOpTest__MinByte() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (byte)(random.Next(0, byte.MinValue)); _data2[i] = (byte)(random.Next(0, byte.MinValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Byte>, byte>(ref _fld1), ref Unsafe.As<Byte, byte>(ref _data1[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Byte>, byte>(ref _fld2), ref Unsafe.As<Byte, byte>(ref _data2[0]), VectorSize); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (byte)(random.Next(0, byte.MinValue)); _data2[i] = (byte)(random.Next(0, byte.MinValue)); } + _dataTable = new SimpleBinaryOpTest__DataTable<Byte>(_data1, _data2, new Byte[ElementCount], VectorSize); + } + + public bool IsSupported => Sse2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse2.Min( + Unsafe.Read<Vector128<Byte>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<Byte>>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse2.Min( + Sse2.LoadVector128((Byte*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Byte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse2.Min( + Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Min), new Type[] { typeof(Vector128<Byte>), typeof(Vector128<Byte>) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector128<Byte>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<Byte>>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Byte>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Min), new Type[] { typeof(Vector128<Byte>), typeof(Vector128<Byte>) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Byte*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Byte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Byte>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Min), new Type[] { typeof(Vector128<Byte>), typeof(Vector128<Byte>) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Byte>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse2.Min( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read<Vector128<Byte>>(_dataTable.inArray1Ptr); + var right = Unsafe.Read<Vector128<Byte>>(_dataTable.inArray2Ptr); + var result = Sse2.Min(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((Byte*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((Byte*)(_dataTable.inArray2Ptr)); + var result = Sse2.Min(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray2Ptr)); + var result = Sse2.Min(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__MinByte(); + var result = Sse2.Min(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse2.Min(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128<Byte> left, Vector128<Byte> right, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[ElementCount]; + Byte[] inArray2 = new Byte[ElementCount]; + Byte[] outArray = new Byte[ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Byte, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[ElementCount]; + Byte[] inArray2 = new Byte[ElementCount]; + Byte[] outArray = new Byte[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Byte, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Byte, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Byte, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Byte[] left, Byte[] right, Byte[] result, [CallerMemberName] string method = "") + { + if (Math.Min(left[0], right[0]) != result[0]) + { + Succeeded = false; + } + else + { + for (var i = 1; i < left.Length; i++) + { + if (Math.Min(left[i], right[i]) != result[i]) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Sse2)}.{nameof(Sse2.Min)}<Byte>: {method} failed:"); + Console.WriteLine($" left: ({string.Join(", ", left)})"); + Console.WriteLine($" right: ({string.Join(", ", right)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Min.Double.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Min.Double.cs new file mode 100644 index 0000000000..4d8e914ff0 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Min.Double.cs @@ -0,0 +1,315 @@ +// 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 MinDouble() + { + var test = new SimpleBinaryOpTest__MinDouble(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + // 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(); + + // 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(); + + // 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 works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + 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__MinDouble + { + private const int VectorSize = 16; + private const int ElementCount = VectorSize / sizeof(Double); + + private static Double[] _data1 = new Double[ElementCount]; + private static Double[] _data2 = new Double[ElementCount]; + + private static Vector128<Double> _clsVar1; + private static Vector128<Double> _clsVar2; + + private Vector128<Double> _fld1; + private Vector128<Double> _fld2; + + private SimpleBinaryOpTest__DataTable<Double> _dataTable; + + static SimpleBinaryOpTest__MinDouble() + { + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (double)(random.NextDouble()); _data2[i] = (double)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Double>, byte>(ref _clsVar1), ref Unsafe.As<Double, byte>(ref _data2[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Double>, byte>(ref _clsVar2), ref Unsafe.As<Double, byte>(ref _data1[0]), VectorSize); + } + + public SimpleBinaryOpTest__MinDouble() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (double)(random.NextDouble()); _data2[i] = (double)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Double>, byte>(ref _fld1), ref Unsafe.As<Double, byte>(ref _data1[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Double>, byte>(ref _fld2), ref Unsafe.As<Double, byte>(ref _data2[0]), VectorSize); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (double)(random.NextDouble()); _data2[i] = (double)(random.NextDouble()); } + _dataTable = new SimpleBinaryOpTest__DataTable<Double>(_data1, _data2, new Double[ElementCount], VectorSize); + } + + public bool IsSupported => Sse2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse2.Min( + Unsafe.Read<Vector128<Double>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<Double>>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse2.Min( + Sse2.LoadVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Double*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse2.Min( + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Min), new Type[] { typeof(Vector128<Double>), typeof(Vector128<Double>) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector128<Double>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<Double>>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Double>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Min), new Type[] { typeof(Vector128<Double>), typeof(Vector128<Double>) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Double*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Double>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Min), new Type[] { typeof(Vector128<Double>), typeof(Vector128<Double>) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Double>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse2.Min( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read<Vector128<Double>>(_dataTable.inArray1Ptr); + var right = Unsafe.Read<Vector128<Double>>(_dataTable.inArray2Ptr); + var result = Sse2.Min(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((Double*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((Double*)(_dataTable.inArray2Ptr)); + var result = Sse2.Min(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray2Ptr)); + var result = Sse2.Min(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__MinDouble(); + var result = Sse2.Min(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse2.Min(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128<Double> left, Vector128<Double> right, void* result, [CallerMemberName] string method = "") + { + Double[] inArray1 = new Double[ElementCount]; + Double[] inArray2 = new Double[ElementCount]; + Double[] outArray = new Double[ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Double[] inArray1 = new Double[ElementCount]; + Double[] inArray2 = new Double[ElementCount]; + Double[] outArray = new Double[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Double[] left, Double[] right, Double[] result, [CallerMemberName] string method = "") + { + if (BitConverter.DoubleToInt64Bits(Math.Min(left[0], right[0])) != BitConverter.DoubleToInt64Bits(result[0])) + { + Succeeded = false; + } + else + { + for (var i = 1; i < left.Length; i++) + { + if (BitConverter.DoubleToInt64Bits(Math.Min(left[i], right[i])) != BitConverter.DoubleToInt64Bits(result[i])) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Sse2)}.{nameof(Sse2.Min)}<Double>: {method} failed:"); + Console.WriteLine($" left: ({string.Join(", ", left)})"); + Console.WriteLine($" right: ({string.Join(", ", right)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Min.Int16.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Min.Int16.cs new file mode 100644 index 0000000000..9019540d3d --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Min.Int16.cs @@ -0,0 +1,315 @@ +// 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 MinInt16() + { + var test = new SimpleBinaryOpTest__MinInt16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + // 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(); + + // 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(); + + // 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 works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + 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__MinInt16 + { + private const int VectorSize = 16; + private const int ElementCount = VectorSize / sizeof(Int16); + + private static Int16[] _data1 = new Int16[ElementCount]; + private static Int16[] _data2 = new Int16[ElementCount]; + + private static Vector128<Int16> _clsVar1; + private static Vector128<Int16> _clsVar2; + + private Vector128<Int16> _fld1; + private Vector128<Int16> _fld2; + + private SimpleBinaryOpTest__DataTable<Int16> _dataTable; + + static SimpleBinaryOpTest__MinInt16() + { + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (short)(random.Next(short.MinValue, short.MinValue)); _data2[i] = (short)(random.Next(short.MinValue, short.MinValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int16>, byte>(ref _clsVar1), ref Unsafe.As<Int16, byte>(ref _data2[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int16>, byte>(ref _clsVar2), ref Unsafe.As<Int16, byte>(ref _data1[0]), VectorSize); + } + + public SimpleBinaryOpTest__MinInt16() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (short)(random.Next(short.MinValue, short.MinValue)); _data2[i] = (short)(random.Next(short.MinValue, short.MinValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int16>, byte>(ref _fld1), ref Unsafe.As<Int16, byte>(ref _data1[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int16>, byte>(ref _fld2), ref Unsafe.As<Int16, byte>(ref _data2[0]), VectorSize); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (short)(random.Next(short.MinValue, short.MinValue)); _data2[i] = (short)(random.Next(short.MinValue, short.MinValue)); } + _dataTable = new SimpleBinaryOpTest__DataTable<Int16>(_data1, _data2, new Int16[ElementCount], VectorSize); + } + + public bool IsSupported => Sse2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse2.Min( + Unsafe.Read<Vector128<Int16>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<Int16>>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse2.Min( + Sse2.LoadVector128((Int16*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Int16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse2.Min( + Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Min), new Type[] { typeof(Vector128<Int16>), typeof(Vector128<Int16>) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector128<Int16>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<Int16>>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Int16>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Min), new Type[] { typeof(Vector128<Int16>), typeof(Vector128<Int16>) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Int16*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Int16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Int16>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Min), new Type[] { typeof(Vector128<Int16>), typeof(Vector128<Int16>) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Int16>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse2.Min( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read<Vector128<Int16>>(_dataTable.inArray1Ptr); + var right = Unsafe.Read<Vector128<Int16>>(_dataTable.inArray2Ptr); + var result = Sse2.Min(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((Int16*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((Int16*)(_dataTable.inArray2Ptr)); + var result = Sse2.Min(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray2Ptr)); + var result = Sse2.Min(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__MinInt16(); + var result = Sse2.Min(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse2.Min(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128<Int16> left, Vector128<Int16> right, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[ElementCount]; + Int16[] inArray2 = new Int16[ElementCount]; + Int16[] outArray = new Int16[ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int16, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[ElementCount]; + Int16[] inArray2 = new Int16[ElementCount]; + Int16[] outArray = new Int16[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int16, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int16, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int16, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int16[] left, Int16[] right, Int16[] result, [CallerMemberName] string method = "") + { + if (Math.Min(left[0], right[0]) != result[0]) + { + Succeeded = false; + } + else + { + for (var i = 1; i < left.Length; i++) + { + if (Math.Min(left[i], right[i]) != result[i]) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Sse2)}.{nameof(Sse2.Min)}<Int16>: {method} failed:"); + Console.WriteLine($" left: ({string.Join(", ", left)})"); + Console.WriteLine($" right: ({string.Join(", ", right)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Min.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Min.cs deleted file mode 100644 index 29f6e90e56..0000000000 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Min.cs +++ /dev/null @@ -1,83 +0,0 @@ -// 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. -// - -using System; -using System.Runtime.Intrinsics; -using System.Runtime.Intrinsics.X86; - -namespace IntelHardwareIntrinsicTest -{ - internal static partial class Program - { - const int Pass = 100; - const int Fail = 0; - - static unsafe int Main(string[] args) - { - int testResult = Pass; - int testsCount = 21; - string methodUnderTestName = nameof(Sse2.Min); - - if (Sse2.IsSupported) - { - using (var doubleTable = TestTableSse2<double>.Create(testsCount)) - using (var shortTable = TestTableSse2<short>.Create(testsCount)) - using (var byteTable = TestTableSse2<byte>.Create(testsCount)) - { - for (int i = 0; i < testsCount; i++) - { - (Vector128<double>, Vector128<double>, Vector128<double>) value = doubleTable[i]; - var result = Sse2.Min(value.Item1, value.Item2); - doubleTable.SetOutArray(result); - } - - for (int i = 0; i < testsCount; i++) - { - (Vector128<short>, Vector128<short>, Vector128<short>) value = shortTable[i]; - var result = Sse2.Min(value.Item1, value.Item2); - shortTable.SetOutArray(result); - } - - for (int i = 0; i < testsCount; i++) - { - (Vector128<byte>, Vector128<byte>, Vector128<byte>) value = byteTable[i]; - var result = Sse2.Min(value.Item1, value.Item2); - byteTable.SetOutArray(result); - } - - CheckMethod<double> checkDouble = (double x, double y, double z, ref double a) => (a = x > y ? y : x) == z; - - if (!doubleTable.CheckResult(checkDouble)) - { - PrintError(doubleTable, methodUnderTestName, "(double x, double y, double z, ref double a) => (a = BitwiseOr(x, y)) == z", checkDouble); - testResult = Fail; - } - - CheckMethod<short> checkInt16 = (short x, short y, short z, ref short a) => (a = x > y ? y : x) == z; - - if (!shortTable.CheckResult(checkInt16)) - { - PrintError(shortTable, methodUnderTestName, "(short x, short y, short z, ref short a) => (a = (short)(x | y)) == z", checkInt16); - testResult = Fail; - } - - CheckMethod<byte> checkByte = (byte x, byte y, byte z, ref byte a) => (a = x > y ? y : x) == z; - - if (!byteTable.CheckResult(checkByte)) - { - PrintError(byteTable, methodUnderTestName, "(byte x, byte y, byte z, ref byte a) => (a = (byte)(x | y)) == z", checkByte); - testResult = Fail; - } - } - } - else - { - Console.WriteLine($"Sse2.IsSupported: {Sse2.IsSupported}, skipped tests of {typeof(Sse2)}.{methodUnderTestName}"); - } - - return testResult; - } - } -} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Min_r.csproj b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Min_r.csproj deleted file mode 100644 index 3d28c6f10a..0000000000 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Min_r.csproj +++ /dev/null @@ -1,38 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" /> - <PropertyGroup> - <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> - <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> - <SchemaVersion>2.0</SchemaVersion> - <ProjectGuid>{78A91B0F-6535-42D7-B64C-948DF295B6BB}</ProjectGuid> - <OutputType>Exe</OutputType> - <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> - <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir> - <AllowUnsafeBlocks>true</AllowUnsafeBlocks> - </PropertyGroup> - <!-- Default configurations to help VS understand the configurations --> - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> - </PropertyGroup> - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' " /> - <ItemGroup> - <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies"> - <Visible>False</Visible> - </CodeAnalysisDependentAssemblyPaths> - </ItemGroup> - <PropertyGroup> - <DebugType>None</DebugType> - <Optimize> - </Optimize> - </PropertyGroup> - <ItemGroup> - <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" /> - </ItemGroup> - <ItemGroup> - <Compile Include="Min.cs" /> - <Compile Include="TestTableSse2.cs" /> - </ItemGroup> - <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" /> - <PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' "> - </PropertyGroup> -</Project>
\ No newline at end of file diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Min_ro.csproj b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Min_ro.csproj deleted file mode 100644 index 0e20e0106d..0000000000 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Min_ro.csproj +++ /dev/null @@ -1,37 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" /> - <PropertyGroup> - <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> - <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> - <SchemaVersion>2.0</SchemaVersion> - <ProjectGuid>{C392B2A4-03ED-4A52-8419-C17085646869}</ProjectGuid> - <OutputType>Exe</OutputType> - <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> - <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir> - <AllowUnsafeBlocks>true</AllowUnsafeBlocks> - </PropertyGroup> - <!-- Default configurations to help VS understand the configurations --> - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> - </PropertyGroup> - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' " /> - <ItemGroup> - <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies"> - <Visible>False</Visible> - </CodeAnalysisDependentAssemblyPaths> - </ItemGroup> - <PropertyGroup> - <DebugType>None</DebugType> - <Optimize>True</Optimize> - </PropertyGroup> - <ItemGroup> - <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" /> - </ItemGroup> - <ItemGroup> - <Compile Include="Min.cs" /> - <Compile Include="TestTableSse2.cs" /> - </ItemGroup> - <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" /> - <PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' "> - </PropertyGroup> -</Project>
\ No newline at end of file diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Multiply.Byte.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Multiply.Byte.cs new file mode 100644 index 0000000000..8507e514bc --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Multiply.Byte.cs @@ -0,0 +1,315 @@ +// 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 MultiplyByte() + { + var test = new SimpleBinaryOpTest__MultiplyByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + // 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(); + + // 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(); + + // 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 works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + 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__MultiplyByte + { + private const int VectorSize = 16; + private const int ElementCount = VectorSize / sizeof(Byte); + + private static Byte[] _data1 = new Byte[ElementCount]; + private static Byte[] _data2 = new Byte[ElementCount]; + + private static Vector128<Byte> _clsVar1; + private static Vector128<Byte> _clsVar2; + + private Vector128<Byte> _fld1; + private Vector128<Byte> _fld2; + + private SimpleBinaryOpTest__DataTable<Byte> _dataTable; + + static SimpleBinaryOpTest__MultiplyByte() + { + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (byte)(random.Next(0, byte.MaxValue)); _data2[i] = (byte)(random.Next(0, byte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Byte>, byte>(ref _clsVar1), ref Unsafe.As<Byte, byte>(ref _data2[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Byte>, byte>(ref _clsVar2), ref Unsafe.As<Byte, byte>(ref _data1[0]), VectorSize); + } + + public SimpleBinaryOpTest__MultiplyByte() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (byte)(random.Next(0, byte.MaxValue)); _data2[i] = (byte)(random.Next(0, byte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Byte>, byte>(ref _fld1), ref Unsafe.As<Byte, byte>(ref _data1[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Byte>, byte>(ref _fld2), ref Unsafe.As<Byte, byte>(ref _data2[0]), VectorSize); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (byte)(random.Next(0, byte.MaxValue)); _data2[i] = (byte)(random.Next(0, byte.MaxValue)); } + _dataTable = new SimpleBinaryOpTest__DataTable<Byte>(_data1, _data2, new Byte[ElementCount], VectorSize); + } + + public bool IsSupported => Sse2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse2.Multiply( + Unsafe.Read<Vector128<Byte>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<Byte>>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse2.Multiply( + Sse2.LoadVector128((Byte*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Byte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse2.Multiply( + Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Multiply), new Type[] { typeof(Vector128<Byte>), typeof(Vector128<Byte>) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector128<Byte>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<Byte>>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Byte>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Multiply), new Type[] { typeof(Vector128<Byte>), typeof(Vector128<Byte>) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Byte*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Byte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Byte>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Multiply), new Type[] { typeof(Vector128<Byte>), typeof(Vector128<Byte>) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Byte>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse2.Multiply( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read<Vector128<Byte>>(_dataTable.inArray1Ptr); + var right = Unsafe.Read<Vector128<Byte>>(_dataTable.inArray2Ptr); + var result = Sse2.Multiply(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((Byte*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((Byte*)(_dataTable.inArray2Ptr)); + var result = Sse2.Multiply(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray2Ptr)); + var result = Sse2.Multiply(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__MultiplyByte(); + var result = Sse2.Multiply(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse2.Multiply(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128<Byte> left, Vector128<Byte> right, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[ElementCount]; + Byte[] inArray2 = new Byte[ElementCount]; + Byte[] outArray = new Byte[ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Byte, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[ElementCount]; + Byte[] inArray2 = new Byte[ElementCount]; + Byte[] outArray = new Byte[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Byte, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Byte, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Byte, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Byte[] left, Byte[] right, Byte[] result, [CallerMemberName] string method = "") + { + if ((byte)(left[0] * right[0]) != result[0]) + { + Succeeded = false; + } + else + { + for (var i = 1; i < left.Length; i++) + { + if ((byte)(left[i] * right[i]) != result[i]) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Sse2)}.{nameof(Sse2.Multiply)}<Byte>: {method} failed:"); + Console.WriteLine($" left: ({string.Join(", ", left)})"); + Console.WriteLine($" right: ({string.Join(", ", right)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Multiply.Double.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Multiply.Double.cs new file mode 100644 index 0000000000..09fa36e52d --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Multiply.Double.cs @@ -0,0 +1,315 @@ +// 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 MultiplyDouble() + { + var test = new SimpleBinaryOpTest__MultiplyDouble(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + // 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(); + + // 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(); + + // 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 works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + 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__MultiplyDouble + { + private const int VectorSize = 16; + private const int ElementCount = VectorSize / sizeof(Double); + + private static Double[] _data1 = new Double[ElementCount]; + private static Double[] _data2 = new Double[ElementCount]; + + private static Vector128<Double> _clsVar1; + private static Vector128<Double> _clsVar2; + + private Vector128<Double> _fld1; + private Vector128<Double> _fld2; + + private SimpleBinaryOpTest__DataTable<Double> _dataTable; + + static SimpleBinaryOpTest__MultiplyDouble() + { + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (double)(random.NextDouble()); _data2[i] = (double)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Double>, byte>(ref _clsVar1), ref Unsafe.As<Double, byte>(ref _data2[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Double>, byte>(ref _clsVar2), ref Unsafe.As<Double, byte>(ref _data1[0]), VectorSize); + } + + public SimpleBinaryOpTest__MultiplyDouble() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (double)(random.NextDouble()); _data2[i] = (double)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Double>, byte>(ref _fld1), ref Unsafe.As<Double, byte>(ref _data1[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Double>, byte>(ref _fld2), ref Unsafe.As<Double, byte>(ref _data2[0]), VectorSize); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (double)(random.NextDouble()); _data2[i] = (double)(random.NextDouble()); } + _dataTable = new SimpleBinaryOpTest__DataTable<Double>(_data1, _data2, new Double[ElementCount], VectorSize); + } + + public bool IsSupported => Sse2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse2.Multiply( + Unsafe.Read<Vector128<Double>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<Double>>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse2.Multiply( + Sse2.LoadVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Double*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse2.Multiply( + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Multiply), new Type[] { typeof(Vector128<Double>), typeof(Vector128<Double>) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector128<Double>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<Double>>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Double>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Multiply), new Type[] { typeof(Vector128<Double>), typeof(Vector128<Double>) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Double*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Double>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Multiply), new Type[] { typeof(Vector128<Double>), typeof(Vector128<Double>) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Double>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse2.Multiply( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read<Vector128<Double>>(_dataTable.inArray1Ptr); + var right = Unsafe.Read<Vector128<Double>>(_dataTable.inArray2Ptr); + var result = Sse2.Multiply(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((Double*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((Double*)(_dataTable.inArray2Ptr)); + var result = Sse2.Multiply(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray2Ptr)); + var result = Sse2.Multiply(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__MultiplyDouble(); + var result = Sse2.Multiply(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse2.Multiply(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128<Double> left, Vector128<Double> right, void* result, [CallerMemberName] string method = "") + { + Double[] inArray1 = new Double[ElementCount]; + Double[] inArray2 = new Double[ElementCount]; + Double[] outArray = new Double[ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Double[] inArray1 = new Double[ElementCount]; + Double[] inArray2 = new Double[ElementCount]; + Double[] outArray = new Double[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Double[] left, Double[] right, Double[] result, [CallerMemberName] string method = "") + { + if (BitConverter.DoubleToInt64Bits(left[0] * right[0]) != BitConverter.DoubleToInt64Bits(result[0])) + { + Succeeded = false; + } + else + { + for (var i = 1; i < left.Length; i++) + { + if (BitConverter.DoubleToInt64Bits(left[i] * right[i]) != BitConverter.DoubleToInt64Bits(result[i])) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Sse2)}.{nameof(Sse2.Multiply)}<Double>: {method} failed:"); + Console.WriteLine($" left: ({string.Join(", ", left)})"); + Console.WriteLine($" right: ({string.Join(", ", right)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Multiply.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Multiply.cs index 701253b9dc..718cfea0b5 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Multiply.cs +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Multiply.cs @@ -22,31 +22,15 @@ namespace IntelHardwareIntrinsicTest if (Sse2.IsSupported) { - using (var doubleTable = TestTableSse2<double>.Create(testsCount)) using (var uintTable = TestTableSse2<uint, ulong>.Create(testsCount, 2.0)) { for (int i = 0; i < testsCount; i++) { - (Vector128<double>, Vector128<double>, Vector128<double>) value = doubleTable[i]; - Vector128<double> result = Sse2.Multiply(value.Item1, value.Item2); - doubleTable.SetOutArray(result); - } - - for (int i = 0; i < testsCount; i++) - { (Vector128<uint>, Vector128<uint>) value = uintTable[i]; Vector128<ulong> result = Sse2.Multiply(value.Item1, value.Item2); uintTable.SetOutArrayU(result); } - CheckMethod<double> checkDouble = (double x, double y, double z, ref double a) => (a = x * y) == z; - - if (!doubleTable.CheckResult(checkDouble)) - { - PrintError(doubleTable, methodUnderTestName, "(double x, double y, double z, ref double a) => (a = x * y) == z", checkDouble); - testResult = Fail; - } - CheckMethodFive<uint, ulong> checkUInt32 = (uint x1, uint x2, uint y1, uint y2, ulong z1, ulong z2, ref ulong a1, ref ulong a2) => { a1 = (ulong)x1 * y1; diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Or.Byte.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Or.Byte.cs new file mode 100644 index 0000000000..6481107fab --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Or.Byte.cs @@ -0,0 +1,315 @@ +// 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 OrByte() + { + var test = new SimpleBinaryOpTest__OrByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + // 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(); + + // 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(); + + // 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 works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + 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__OrByte + { + private const int VectorSize = 16; + private const int ElementCount = VectorSize / sizeof(Byte); + + private static Byte[] _data1 = new Byte[ElementCount]; + private static Byte[] _data2 = new Byte[ElementCount]; + + private static Vector128<Byte> _clsVar1; + private static Vector128<Byte> _clsVar2; + + private Vector128<Byte> _fld1; + private Vector128<Byte> _fld2; + + private SimpleBinaryOpTest__DataTable<Byte> _dataTable; + + static SimpleBinaryOpTest__OrByte() + { + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (byte)(random.Next(0, byte.MaxValue)); _data2[i] = (byte)(random.Next(0, byte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Byte>, byte>(ref _clsVar1), ref Unsafe.As<Byte, byte>(ref _data2[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Byte>, byte>(ref _clsVar2), ref Unsafe.As<Byte, byte>(ref _data1[0]), VectorSize); + } + + public SimpleBinaryOpTest__OrByte() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (byte)(random.Next(0, byte.MaxValue)); _data2[i] = (byte)(random.Next(0, byte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Byte>, byte>(ref _fld1), ref Unsafe.As<Byte, byte>(ref _data1[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Byte>, byte>(ref _fld2), ref Unsafe.As<Byte, byte>(ref _data2[0]), VectorSize); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (byte)(random.Next(0, byte.MaxValue)); _data2[i] = (byte)(random.Next(0, byte.MaxValue)); } + _dataTable = new SimpleBinaryOpTest__DataTable<Byte>(_data1, _data2, new Byte[ElementCount], VectorSize); + } + + public bool IsSupported => Sse2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse2.Or( + Unsafe.Read<Vector128<Byte>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<Byte>>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse2.Or( + Sse2.LoadVector128((Byte*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Byte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse2.Or( + Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Or), new Type[] { typeof(Vector128<Byte>), typeof(Vector128<Byte>) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector128<Byte>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<Byte>>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Byte>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Or), new Type[] { typeof(Vector128<Byte>), typeof(Vector128<Byte>) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Byte*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Byte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Byte>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Or), new Type[] { typeof(Vector128<Byte>), typeof(Vector128<Byte>) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Byte>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse2.Or( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read<Vector128<Byte>>(_dataTable.inArray1Ptr); + var right = Unsafe.Read<Vector128<Byte>>(_dataTable.inArray2Ptr); + var result = Sse2.Or(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((Byte*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((Byte*)(_dataTable.inArray2Ptr)); + var result = Sse2.Or(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray2Ptr)); + var result = Sse2.Or(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__OrByte(); + var result = Sse2.Or(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse2.Or(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128<Byte> left, Vector128<Byte> right, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[ElementCount]; + Byte[] inArray2 = new Byte[ElementCount]; + Byte[] outArray = new Byte[ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Byte, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[ElementCount]; + Byte[] inArray2 = new Byte[ElementCount]; + Byte[] outArray = new Byte[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Byte, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Byte, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Byte, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Byte[] left, Byte[] right, Byte[] result, [CallerMemberName] string method = "") + { + if ((byte)(left[0] | right[0]) != result[0]) + { + Succeeded = false; + } + else + { + for (var i = 1; i < left.Length; i++) + { + if ((byte)(left[i] | right[i]) != result[i]) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Sse2)}.{nameof(Sse2.Or)}<Byte>: {method} failed:"); + Console.WriteLine($" left: ({string.Join(", ", left)})"); + Console.WriteLine($" right: ({string.Join(", ", right)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Or.Double.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Or.Double.cs new file mode 100644 index 0000000000..bfa8d33473 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Or.Double.cs @@ -0,0 +1,315 @@ +// 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 OrDouble() + { + var test = new SimpleBinaryOpTest__OrDouble(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + // 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(); + + // 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(); + + // 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 works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + 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__OrDouble + { + private const int VectorSize = 16; + private const int ElementCount = VectorSize / sizeof(Double); + + private static Double[] _data1 = new Double[ElementCount]; + private static Double[] _data2 = new Double[ElementCount]; + + private static Vector128<Double> _clsVar1; + private static Vector128<Double> _clsVar2; + + private Vector128<Double> _fld1; + private Vector128<Double> _fld2; + + private SimpleBinaryOpTest__DataTable<Double> _dataTable; + + static SimpleBinaryOpTest__OrDouble() + { + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (double)(random.NextDouble()); _data2[i] = (double)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Double>, byte>(ref _clsVar1), ref Unsafe.As<Double, byte>(ref _data2[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Double>, byte>(ref _clsVar2), ref Unsafe.As<Double, byte>(ref _data1[0]), VectorSize); + } + + public SimpleBinaryOpTest__OrDouble() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (double)(random.NextDouble()); _data2[i] = (double)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Double>, byte>(ref _fld1), ref Unsafe.As<Double, byte>(ref _data1[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Double>, byte>(ref _fld2), ref Unsafe.As<Double, byte>(ref _data2[0]), VectorSize); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (double)(random.NextDouble()); _data2[i] = (double)(random.NextDouble()); } + _dataTable = new SimpleBinaryOpTest__DataTable<Double>(_data1, _data2, new Double[ElementCount], VectorSize); + } + + public bool IsSupported => Sse2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse2.Or( + Unsafe.Read<Vector128<Double>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<Double>>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse2.Or( + Sse2.LoadVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Double*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse2.Or( + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Or), new Type[] { typeof(Vector128<Double>), typeof(Vector128<Double>) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector128<Double>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<Double>>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Double>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Or), new Type[] { typeof(Vector128<Double>), typeof(Vector128<Double>) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Double*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Double>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Or), new Type[] { typeof(Vector128<Double>), typeof(Vector128<Double>) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Double>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse2.Or( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read<Vector128<Double>>(_dataTable.inArray1Ptr); + var right = Unsafe.Read<Vector128<Double>>(_dataTable.inArray2Ptr); + var result = Sse2.Or(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((Double*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((Double*)(_dataTable.inArray2Ptr)); + var result = Sse2.Or(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray2Ptr)); + var result = Sse2.Or(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__OrDouble(); + var result = Sse2.Or(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse2.Or(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128<Double> left, Vector128<Double> right, void* result, [CallerMemberName] string method = "") + { + Double[] inArray1 = new Double[ElementCount]; + Double[] inArray2 = new Double[ElementCount]; + Double[] outArray = new Double[ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Double[] inArray1 = new Double[ElementCount]; + Double[] inArray2 = new Double[ElementCount]; + Double[] outArray = new Double[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Double[] left, Double[] right, Double[] result, [CallerMemberName] string method = "") + { + if ((BitConverter.DoubleToInt64Bits(left[0]) | BitConverter.DoubleToInt64Bits(right[0])) != BitConverter.DoubleToInt64Bits(result[0])) + { + Succeeded = false; + } + else + { + for (var i = 1; i < left.Length; i++) + { + if ((BitConverter.DoubleToInt64Bits(left[i]) | BitConverter.DoubleToInt64Bits(right[i])) != BitConverter.DoubleToInt64Bits(result[i])) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Sse2)}.{nameof(Sse2.Or)}<Double>: {method} failed:"); + Console.WriteLine($" left: ({string.Join(", ", left)})"); + Console.WriteLine($" right: ({string.Join(", ", right)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Or.Int16.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Or.Int16.cs new file mode 100644 index 0000000000..2d3fe08199 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Or.Int16.cs @@ -0,0 +1,315 @@ +// 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 OrInt16() + { + var test = new SimpleBinaryOpTest__OrInt16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + // 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(); + + // 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(); + + // 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 works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + 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__OrInt16 + { + private const int VectorSize = 16; + private const int ElementCount = VectorSize / sizeof(Int16); + + private static Int16[] _data1 = new Int16[ElementCount]; + private static Int16[] _data2 = new Int16[ElementCount]; + + private static Vector128<Int16> _clsVar1; + private static Vector128<Int16> _clsVar2; + + private Vector128<Int16> _fld1; + private Vector128<Int16> _fld2; + + private SimpleBinaryOpTest__DataTable<Int16> _dataTable; + + static SimpleBinaryOpTest__OrInt16() + { + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (short)(random.Next(short.MinValue, short.MaxValue)); _data2[i] = (short)(random.Next(short.MinValue, short.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int16>, byte>(ref _clsVar1), ref Unsafe.As<Int16, byte>(ref _data2[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int16>, byte>(ref _clsVar2), ref Unsafe.As<Int16, byte>(ref _data1[0]), VectorSize); + } + + public SimpleBinaryOpTest__OrInt16() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (short)(random.Next(short.MinValue, short.MaxValue)); _data2[i] = (short)(random.Next(short.MinValue, short.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int16>, byte>(ref _fld1), ref Unsafe.As<Int16, byte>(ref _data1[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int16>, byte>(ref _fld2), ref Unsafe.As<Int16, byte>(ref _data2[0]), VectorSize); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (short)(random.Next(short.MinValue, short.MaxValue)); _data2[i] = (short)(random.Next(short.MinValue, short.MaxValue)); } + _dataTable = new SimpleBinaryOpTest__DataTable<Int16>(_data1, _data2, new Int16[ElementCount], VectorSize); + } + + public bool IsSupported => Sse2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse2.Or( + Unsafe.Read<Vector128<Int16>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<Int16>>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse2.Or( + Sse2.LoadVector128((Int16*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Int16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse2.Or( + Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Or), new Type[] { typeof(Vector128<Int16>), typeof(Vector128<Int16>) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector128<Int16>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<Int16>>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Int16>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Or), new Type[] { typeof(Vector128<Int16>), typeof(Vector128<Int16>) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Int16*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Int16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Int16>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Or), new Type[] { typeof(Vector128<Int16>), typeof(Vector128<Int16>) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Int16>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse2.Or( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read<Vector128<Int16>>(_dataTable.inArray1Ptr); + var right = Unsafe.Read<Vector128<Int16>>(_dataTable.inArray2Ptr); + var result = Sse2.Or(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((Int16*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((Int16*)(_dataTable.inArray2Ptr)); + var result = Sse2.Or(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray2Ptr)); + var result = Sse2.Or(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__OrInt16(); + var result = Sse2.Or(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse2.Or(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128<Int16> left, Vector128<Int16> right, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[ElementCount]; + Int16[] inArray2 = new Int16[ElementCount]; + Int16[] outArray = new Int16[ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int16, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[ElementCount]; + Int16[] inArray2 = new Int16[ElementCount]; + Int16[] outArray = new Int16[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int16, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int16, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int16, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int16[] left, Int16[] right, Int16[] result, [CallerMemberName] string method = "") + { + if ((short)(left[0] | right[0]) != result[0]) + { + Succeeded = false; + } + else + { + for (var i = 1; i < left.Length; i++) + { + if ((short)(left[i] | right[i]) != result[i]) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Sse2)}.{nameof(Sse2.Or)}<Int16>: {method} failed:"); + Console.WriteLine($" left: ({string.Join(", ", left)})"); + Console.WriteLine($" right: ({string.Join(", ", right)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Or.Int32.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Or.Int32.cs new file mode 100644 index 0000000000..fbe5b1ced9 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Or.Int32.cs @@ -0,0 +1,315 @@ +// 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 OrInt32() + { + var test = new SimpleBinaryOpTest__OrInt32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + // 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(); + + // 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(); + + // 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 works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + 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__OrInt32 + { + private const int VectorSize = 16; + private const int ElementCount = VectorSize / sizeof(Int32); + + private static Int32[] _data1 = new Int32[ElementCount]; + private static Int32[] _data2 = new Int32[ElementCount]; + + private static Vector128<Int32> _clsVar1; + private static Vector128<Int32> _clsVar2; + + private Vector128<Int32> _fld1; + private Vector128<Int32> _fld2; + + private SimpleBinaryOpTest__DataTable<Int32> _dataTable; + + static SimpleBinaryOpTest__OrInt32() + { + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (int)(random.Next(int.MinValue, int.MaxValue)); _data2[i] = (int)(random.Next(int.MinValue, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int32>, byte>(ref _clsVar1), ref Unsafe.As<Int32, byte>(ref _data2[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int32>, byte>(ref _clsVar2), ref Unsafe.As<Int32, byte>(ref _data1[0]), VectorSize); + } + + public SimpleBinaryOpTest__OrInt32() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (int)(random.Next(int.MinValue, int.MaxValue)); _data2[i] = (int)(random.Next(int.MinValue, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int32>, byte>(ref _fld1), ref Unsafe.As<Int32, byte>(ref _data1[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int32>, byte>(ref _fld2), ref Unsafe.As<Int32, byte>(ref _data2[0]), VectorSize); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (int)(random.Next(int.MinValue, int.MaxValue)); _data2[i] = (int)(random.Next(int.MinValue, int.MaxValue)); } + _dataTable = new SimpleBinaryOpTest__DataTable<Int32>(_data1, _data2, new Int32[ElementCount], VectorSize); + } + + public bool IsSupported => Sse2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse2.Or( + Unsafe.Read<Vector128<Int32>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<Int32>>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse2.Or( + Sse2.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Int32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse2.Or( + Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Or), new Type[] { typeof(Vector128<Int32>), typeof(Vector128<Int32>) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector128<Int32>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<Int32>>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Int32>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Or), new Type[] { typeof(Vector128<Int32>), typeof(Vector128<Int32>) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Int32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Int32>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Or), new Type[] { typeof(Vector128<Int32>), typeof(Vector128<Int32>) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Int32>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse2.Or( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read<Vector128<Int32>>(_dataTable.inArray1Ptr); + var right = Unsafe.Read<Vector128<Int32>>(_dataTable.inArray2Ptr); + var result = Sse2.Or(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((Int32*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((Int32*)(_dataTable.inArray2Ptr)); + var result = Sse2.Or(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray2Ptr)); + var result = Sse2.Or(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__OrInt32(); + var result = Sse2.Or(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse2.Or(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128<Int32> left, Vector128<Int32> right, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[ElementCount]; + Int32[] inArray2 = new Int32[ElementCount]; + Int32[] outArray = new Int32[ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int32, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[ElementCount]; + Int32[] inArray2 = new Int32[ElementCount]; + Int32[] outArray = new Int32[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int32, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int32, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int32, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int32[] left, Int32[] right, Int32[] result, [CallerMemberName] string method = "") + { + if ((int)(left[0] | right[0]) != result[0]) + { + Succeeded = false; + } + else + { + for (var i = 1; i < left.Length; i++) + { + if ((int)(left[i] | right[i]) != result[i]) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Sse2)}.{nameof(Sse2.Or)}<Int32>: {method} failed:"); + Console.WriteLine($" left: ({string.Join(", ", left)})"); + Console.WriteLine($" right: ({string.Join(", ", right)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Or.Int64.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Or.Int64.cs new file mode 100644 index 0000000000..861aed23c9 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Or.Int64.cs @@ -0,0 +1,315 @@ +// 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 OrInt64() + { + var test = new SimpleBinaryOpTest__OrInt64(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + // 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(); + + // 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(); + + // 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 works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + 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__OrInt64 + { + private const int VectorSize = 16; + private const int ElementCount = VectorSize / sizeof(Int64); + + private static Int64[] _data1 = new Int64[ElementCount]; + private static Int64[] _data2 = new Int64[ElementCount]; + + private static Vector128<Int64> _clsVar1; + private static Vector128<Int64> _clsVar2; + + private Vector128<Int64> _fld1; + private Vector128<Int64> _fld2; + + private SimpleBinaryOpTest__DataTable<Int64> _dataTable; + + static SimpleBinaryOpTest__OrInt64() + { + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (long)(random.Next(int.MinValue, int.MaxValue)); _data2[i] = (long)(random.Next(int.MinValue, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int64>, byte>(ref _clsVar1), ref Unsafe.As<Int64, byte>(ref _data2[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int64>, byte>(ref _clsVar2), ref Unsafe.As<Int64, byte>(ref _data1[0]), VectorSize); + } + + public SimpleBinaryOpTest__OrInt64() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (long)(random.Next(int.MinValue, int.MaxValue)); _data2[i] = (long)(random.Next(int.MinValue, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int64>, byte>(ref _fld1), ref Unsafe.As<Int64, byte>(ref _data1[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int64>, byte>(ref _fld2), ref Unsafe.As<Int64, byte>(ref _data2[0]), VectorSize); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (long)(random.Next(int.MinValue, int.MaxValue)); _data2[i] = (long)(random.Next(int.MinValue, int.MaxValue)); } + _dataTable = new SimpleBinaryOpTest__DataTable<Int64>(_data1, _data2, new Int64[ElementCount], VectorSize); + } + + public bool IsSupported => Sse2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse2.Or( + Unsafe.Read<Vector128<Int64>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<Int64>>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse2.Or( + Sse2.LoadVector128((Int64*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Int64*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse2.Or( + Sse2.LoadAlignedVector128((Int64*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Int64*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Or), new Type[] { typeof(Vector128<Int64>), typeof(Vector128<Int64>) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector128<Int64>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<Int64>>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Int64>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Or), new Type[] { typeof(Vector128<Int64>), typeof(Vector128<Int64>) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Int64*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Int64*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Int64>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Or), new Type[] { typeof(Vector128<Int64>), typeof(Vector128<Int64>) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Int64*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Int64*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Int64>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse2.Or( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read<Vector128<Int64>>(_dataTable.inArray1Ptr); + var right = Unsafe.Read<Vector128<Int64>>(_dataTable.inArray2Ptr); + var result = Sse2.Or(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((Int64*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((Int64*)(_dataTable.inArray2Ptr)); + var result = Sse2.Or(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((Int64*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((Int64*)(_dataTable.inArray2Ptr)); + var result = Sse2.Or(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__OrInt64(); + var result = Sse2.Or(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse2.Or(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128<Int64> left, Vector128<Int64> right, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[ElementCount]; + Int64[] inArray2 = new Int64[ElementCount]; + Int64[] outArray = new Int64[ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int64, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[ElementCount]; + Int64[] inArray2 = new Int64[ElementCount]; + Int64[] outArray = new Int64[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int64, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int64, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int64, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int64[] left, Int64[] right, Int64[] result, [CallerMemberName] string method = "") + { + if ((long)(left[0] | right[0]) != result[0]) + { + Succeeded = false; + } + else + { + for (var i = 1; i < left.Length; i++) + { + if ((long)(left[i] | right[i]) != result[i]) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Sse2)}.{nameof(Sse2.Or)}<Int64>: {method} failed:"); + Console.WriteLine($" left: ({string.Join(", ", left)})"); + Console.WriteLine($" right: ({string.Join(", ", right)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Or.SByte.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Or.SByte.cs new file mode 100644 index 0000000000..56a3cfb4aa --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Or.SByte.cs @@ -0,0 +1,315 @@ +// 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 OrSByte() + { + var test = new SimpleBinaryOpTest__OrSByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + // 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(); + + // 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(); + + // 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 works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + 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__OrSByte + { + private const int VectorSize = 16; + private const int ElementCount = VectorSize / sizeof(SByte); + + private static SByte[] _data1 = new SByte[ElementCount]; + private static SByte[] _data2 = new SByte[ElementCount]; + + private static Vector128<SByte> _clsVar1; + private static Vector128<SByte> _clsVar2; + + private Vector128<SByte> _fld1; + private Vector128<SByte> _fld2; + + private SimpleBinaryOpTest__DataTable<SByte> _dataTable; + + static SimpleBinaryOpTest__OrSByte() + { + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue)); _data2[i] = (sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<SByte>, byte>(ref _clsVar1), ref Unsafe.As<SByte, byte>(ref _data2[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<SByte>, byte>(ref _clsVar2), ref Unsafe.As<SByte, byte>(ref _data1[0]), VectorSize); + } + + public SimpleBinaryOpTest__OrSByte() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue)); _data2[i] = (sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<SByte>, byte>(ref _fld1), ref Unsafe.As<SByte, byte>(ref _data1[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<SByte>, byte>(ref _fld2), ref Unsafe.As<SByte, byte>(ref _data2[0]), VectorSize); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue)); _data2[i] = (sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue)); } + _dataTable = new SimpleBinaryOpTest__DataTable<SByte>(_data1, _data2, new SByte[ElementCount], VectorSize); + } + + public bool IsSupported => Sse2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse2.Or( + Unsafe.Read<Vector128<SByte>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<SByte>>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse2.Or( + Sse2.LoadVector128((SByte*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((SByte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse2.Or( + Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Or), new Type[] { typeof(Vector128<SByte>), typeof(Vector128<SByte>) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector128<SByte>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<SByte>>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<SByte>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Or), new Type[] { typeof(Vector128<SByte>), typeof(Vector128<SByte>) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((SByte*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((SByte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<SByte>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Or), new Type[] { typeof(Vector128<SByte>), typeof(Vector128<SByte>) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<SByte>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse2.Or( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read<Vector128<SByte>>(_dataTable.inArray1Ptr); + var right = Unsafe.Read<Vector128<SByte>>(_dataTable.inArray2Ptr); + var result = Sse2.Or(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((SByte*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((SByte*)(_dataTable.inArray2Ptr)); + var result = Sse2.Or(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArray2Ptr)); + var result = Sse2.Or(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__OrSByte(); + var result = Sse2.Or(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse2.Or(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128<SByte> left, Vector128<SByte> right, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[ElementCount]; + SByte[] inArray2 = new SByte[ElementCount]; + SByte[] outArray = new SByte[ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<SByte, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[ElementCount]; + SByte[] inArray2 = new SByte[ElementCount]; + SByte[] outArray = new SByte[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<SByte, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<SByte, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<SByte, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(SByte[] left, SByte[] right, SByte[] result, [CallerMemberName] string method = "") + { + if ((sbyte)(left[0] | right[0]) != result[0]) + { + Succeeded = false; + } + else + { + for (var i = 1; i < left.Length; i++) + { + if ((sbyte)(left[i] | right[i]) != result[i]) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Sse2)}.{nameof(Sse2.Or)}<SByte>: {method} failed:"); + Console.WriteLine($" left: ({string.Join(", ", left)})"); + Console.WriteLine($" right: ({string.Join(", ", right)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Or.UInt16.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Or.UInt16.cs new file mode 100644 index 0000000000..ea151578a3 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Or.UInt16.cs @@ -0,0 +1,315 @@ +// 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 OrUInt16() + { + var test = new SimpleBinaryOpTest__OrUInt16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + // 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(); + + // 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(); + + // 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 works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + 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__OrUInt16 + { + private const int VectorSize = 16; + private const int ElementCount = VectorSize / sizeof(UInt16); + + private static UInt16[] _data1 = new UInt16[ElementCount]; + private static UInt16[] _data2 = new UInt16[ElementCount]; + + private static Vector128<UInt16> _clsVar1; + private static Vector128<UInt16> _clsVar2; + + private Vector128<UInt16> _fld1; + private Vector128<UInt16> _fld2; + + private SimpleBinaryOpTest__DataTable<UInt16> _dataTable; + + static SimpleBinaryOpTest__OrUInt16() + { + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (ushort)(random.Next(0, ushort.MaxValue)); _data2[i] = (ushort)(random.Next(0, ushort.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt16>, byte>(ref _clsVar1), ref Unsafe.As<UInt16, byte>(ref _data2[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt16>, byte>(ref _clsVar2), ref Unsafe.As<UInt16, byte>(ref _data1[0]), VectorSize); + } + + public SimpleBinaryOpTest__OrUInt16() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (ushort)(random.Next(0, ushort.MaxValue)); _data2[i] = (ushort)(random.Next(0, ushort.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt16>, byte>(ref _fld1), ref Unsafe.As<UInt16, byte>(ref _data1[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt16>, byte>(ref _fld2), ref Unsafe.As<UInt16, byte>(ref _data2[0]), VectorSize); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (ushort)(random.Next(0, ushort.MaxValue)); _data2[i] = (ushort)(random.Next(0, ushort.MaxValue)); } + _dataTable = new SimpleBinaryOpTest__DataTable<UInt16>(_data1, _data2, new UInt16[ElementCount], VectorSize); + } + + public bool IsSupported => Sse2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse2.Or( + Unsafe.Read<Vector128<UInt16>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<UInt16>>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse2.Or( + Sse2.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse2.Or( + Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Or), new Type[] { typeof(Vector128<UInt16>), typeof(Vector128<UInt16>) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector128<UInt16>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<UInt16>>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<UInt16>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Or), new Type[] { typeof(Vector128<UInt16>), typeof(Vector128<UInt16>) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<UInt16>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Or), new Type[] { typeof(Vector128<UInt16>), typeof(Vector128<UInt16>) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<UInt16>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse2.Or( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read<Vector128<UInt16>>(_dataTable.inArray1Ptr); + var right = Unsafe.Read<Vector128<UInt16>>(_dataTable.inArray2Ptr); + var result = Sse2.Or(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)); + var result = Sse2.Or(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArray2Ptr)); + var result = Sse2.Or(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__OrUInt16(); + var result = Sse2.Or(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse2.Or(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128<UInt16> left, Vector128<UInt16> right, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[ElementCount]; + UInt16[] inArray2 = new UInt16[ElementCount]; + UInt16[] outArray = new UInt16[ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt16, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[ElementCount]; + UInt16[] inArray2 = new UInt16[ElementCount]; + UInt16[] outArray = new UInt16[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt16, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt16, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt16, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt16[] left, UInt16[] right, UInt16[] result, [CallerMemberName] string method = "") + { + if ((ushort)(left[0] | right[0]) != result[0]) + { + Succeeded = false; + } + else + { + for (var i = 1; i < left.Length; i++) + { + if ((ushort)(left[i] | right[i]) != result[i]) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Sse2)}.{nameof(Sse2.Or)}<UInt16>: {method} failed:"); + Console.WriteLine($" left: ({string.Join(", ", left)})"); + Console.WriteLine($" right: ({string.Join(", ", right)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Or.UInt32.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Or.UInt32.cs new file mode 100644 index 0000000000..b03776135c --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Or.UInt32.cs @@ -0,0 +1,315 @@ +// 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 OrUInt32() + { + var test = new SimpleBinaryOpTest__OrUInt32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + // 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(); + + // 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(); + + // 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 works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + 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__OrUInt32 + { + private const int VectorSize = 16; + private const int ElementCount = VectorSize / sizeof(UInt32); + + private static UInt32[] _data1 = new UInt32[ElementCount]; + private static UInt32[] _data2 = new UInt32[ElementCount]; + + private static Vector128<UInt32> _clsVar1; + private static Vector128<UInt32> _clsVar2; + + private Vector128<UInt32> _fld1; + private Vector128<UInt32> _fld2; + + private SimpleBinaryOpTest__DataTable<UInt32> _dataTable; + + static SimpleBinaryOpTest__OrUInt32() + { + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (uint)(random.Next(0, int.MaxValue)); _data2[i] = (uint)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt32>, byte>(ref _clsVar1), ref Unsafe.As<UInt32, byte>(ref _data2[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt32>, byte>(ref _clsVar2), ref Unsafe.As<UInt32, byte>(ref _data1[0]), VectorSize); + } + + public SimpleBinaryOpTest__OrUInt32() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (uint)(random.Next(0, int.MaxValue)); _data2[i] = (uint)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt32>, byte>(ref _fld1), ref Unsafe.As<UInt32, byte>(ref _data1[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt32>, byte>(ref _fld2), ref Unsafe.As<UInt32, byte>(ref _data2[0]), VectorSize); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (uint)(random.Next(0, int.MaxValue)); _data2[i] = (uint)(random.Next(0, int.MaxValue)); } + _dataTable = new SimpleBinaryOpTest__DataTable<UInt32>(_data1, _data2, new UInt32[ElementCount], VectorSize); + } + + public bool IsSupported => Sse2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse2.Or( + Unsafe.Read<Vector128<UInt32>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<UInt32>>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse2.Or( + Sse2.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse2.Or( + Sse2.LoadAlignedVector128((UInt32*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((UInt32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Or), new Type[] { typeof(Vector128<UInt32>), typeof(Vector128<UInt32>) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector128<UInt32>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<UInt32>>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<UInt32>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Or), new Type[] { typeof(Vector128<UInt32>), typeof(Vector128<UInt32>) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<UInt32>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Or), new Type[] { typeof(Vector128<UInt32>), typeof(Vector128<UInt32>) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((UInt32*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((UInt32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<UInt32>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse2.Or( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read<Vector128<UInt32>>(_dataTable.inArray1Ptr); + var right = Unsafe.Read<Vector128<UInt32>>(_dataTable.inArray2Ptr); + var result = Sse2.Or(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)); + var result = Sse2.Or(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((UInt32*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((UInt32*)(_dataTable.inArray2Ptr)); + var result = Sse2.Or(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__OrUInt32(); + var result = Sse2.Or(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse2.Or(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128<UInt32> left, Vector128<UInt32> right, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[ElementCount]; + UInt32[] inArray2 = new UInt32[ElementCount]; + UInt32[] outArray = new UInt32[ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt32, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[ElementCount]; + UInt32[] inArray2 = new UInt32[ElementCount]; + UInt32[] outArray = new UInt32[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt32, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt32, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt32, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt32[] left, UInt32[] right, UInt32[] result, [CallerMemberName] string method = "") + { + if ((uint)(left[0] | right[0]) != result[0]) + { + Succeeded = false; + } + else + { + for (var i = 1; i < left.Length; i++) + { + if ((uint)(left[i] | right[i]) != result[i]) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Sse2)}.{nameof(Sse2.Or)}<UInt32>: {method} failed:"); + Console.WriteLine($" left: ({string.Join(", ", left)})"); + Console.WriteLine($" right: ({string.Join(", ", right)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Or.UInt64.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Or.UInt64.cs new file mode 100644 index 0000000000..40e22b43d7 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Or.UInt64.cs @@ -0,0 +1,315 @@ +// 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 OrUInt64() + { + var test = new SimpleBinaryOpTest__OrUInt64(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + // 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(); + + // 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(); + + // 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 works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + 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__OrUInt64 + { + private const int VectorSize = 16; + private const int ElementCount = VectorSize / sizeof(UInt64); + + private static UInt64[] _data1 = new UInt64[ElementCount]; + private static UInt64[] _data2 = new UInt64[ElementCount]; + + private static Vector128<UInt64> _clsVar1; + private static Vector128<UInt64> _clsVar2; + + private Vector128<UInt64> _fld1; + private Vector128<UInt64> _fld2; + + private SimpleBinaryOpTest__DataTable<UInt64> _dataTable; + + static SimpleBinaryOpTest__OrUInt64() + { + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (ulong)(random.Next(0, int.MaxValue)); _data2[i] = (ulong)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt64>, byte>(ref _clsVar1), ref Unsafe.As<UInt64, byte>(ref _data2[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt64>, byte>(ref _clsVar2), ref Unsafe.As<UInt64, byte>(ref _data1[0]), VectorSize); + } + + public SimpleBinaryOpTest__OrUInt64() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (ulong)(random.Next(0, int.MaxValue)); _data2[i] = (ulong)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt64>, byte>(ref _fld1), ref Unsafe.As<UInt64, byte>(ref _data1[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt64>, byte>(ref _fld2), ref Unsafe.As<UInt64, byte>(ref _data2[0]), VectorSize); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (ulong)(random.Next(0, int.MaxValue)); _data2[i] = (ulong)(random.Next(0, int.MaxValue)); } + _dataTable = new SimpleBinaryOpTest__DataTable<UInt64>(_data1, _data2, new UInt64[ElementCount], VectorSize); + } + + public bool IsSupported => Sse2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse2.Or( + Unsafe.Read<Vector128<UInt64>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<UInt64>>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse2.Or( + Sse2.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((UInt64*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse2.Or( + Sse2.LoadAlignedVector128((UInt64*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((UInt64*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Or), new Type[] { typeof(Vector128<UInt64>), typeof(Vector128<UInt64>) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector128<UInt64>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<UInt64>>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<UInt64>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Or), new Type[] { typeof(Vector128<UInt64>), typeof(Vector128<UInt64>) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((UInt64*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<UInt64>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Or), new Type[] { typeof(Vector128<UInt64>), typeof(Vector128<UInt64>) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((UInt64*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((UInt64*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<UInt64>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse2.Or( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read<Vector128<UInt64>>(_dataTable.inArray1Ptr); + var right = Unsafe.Read<Vector128<UInt64>>(_dataTable.inArray2Ptr); + var result = Sse2.Or(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((UInt64*)(_dataTable.inArray2Ptr)); + var result = Sse2.Or(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((UInt64*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((UInt64*)(_dataTable.inArray2Ptr)); + var result = Sse2.Or(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__OrUInt64(); + var result = Sse2.Or(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse2.Or(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128<UInt64> left, Vector128<UInt64> right, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray1 = new UInt64[ElementCount]; + UInt64[] inArray2 = new UInt64[ElementCount]; + UInt64[] outArray = new UInt64[ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt64, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray1 = new UInt64[ElementCount]; + UInt64[] inArray2 = new UInt64[ElementCount]; + UInt64[] outArray = new UInt64[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt64, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt64, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt64, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt64[] left, UInt64[] right, UInt64[] result, [CallerMemberName] string method = "") + { + if ((ulong)(left[0] | right[0]) != result[0]) + { + Succeeded = false; + } + else + { + for (var i = 1; i < left.Length; i++) + { + if ((ulong)(left[i] | right[i]) != result[i]) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Sse2)}.{nameof(Sse2.Or)}<UInt64>: {method} failed:"); + Console.WriteLine($" left: ({string.Join(", ", left)})"); + Console.WriteLine($" right: ({string.Join(", ", right)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Or.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Or.cs deleted file mode 100644 index 7958224a74..0000000000 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Or.cs +++ /dev/null @@ -1,187 +0,0 @@ -// 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. -// - -using System; -using System.Runtime.Intrinsics; -using System.Runtime.Intrinsics.X86; - -namespace IntelHardwareIntrinsicTest -{ - internal static partial class Program - { - const int Pass = 100; - const int Fail = 0; - - static unsafe int Main(string[] args) - { - int testResult = Pass; - int testsCount = 21; - string methodUnderTestName = nameof(Sse2.Or); - - if (Sse2.IsSupported) - { - using (var doubleTable = TestTableSse2<double>.Create(testsCount)) - using (var longTable = TestTableSse2<long>.Create(testsCount)) - using (var ulongTable = TestTableSse2<ulong>.Create(testsCount)) - using (var intTable = TestTableSse2<int>.Create(testsCount)) - using (var uintTable = TestTableSse2<uint>.Create(testsCount)) - using (var shortTable = TestTableSse2<short>.Create(testsCount)) - using (var ushortTable = TestTableSse2<ushort>.Create(testsCount)) - using (var sbyteTable = TestTableSse2<sbyte>.Create(testsCount)) - using (var byteTable = TestTableSse2<byte>.Create(testsCount)) - { - for (int i = 0; i < testsCount; i++) - { - (Vector128<double>, Vector128<double>, Vector128<double>) value = doubleTable[i]; - var result = Sse2.Or(value.Item1, value.Item2); - doubleTable.SetOutArray(result); - } - - for (int i = 0; i < testsCount; i++) - { - (Vector128<long>, Vector128<long>, Vector128<long>) value = longTable[i]; - var result = Sse2.Or(value.Item1, value.Item2); - longTable.SetOutArray(result); - } - - for (int i = 0; i < testsCount; i++) - { - (Vector128<ulong>, Vector128<ulong>, Vector128<ulong>) value = ulongTable[i]; - var result = Sse2.Or(value.Item1, value.Item2); - ulongTable.SetOutArray(result); - } - - for (int i = 0; i < testsCount; i++) - { - (Vector128<int>, Vector128<int>, Vector128<int>) value = intTable[i]; - var result = Sse2.Or(value.Item1, value.Item2); - intTable.SetOutArray(result); - } - - for (int i = 0; i < testsCount; i++) - { - (Vector128<uint>, Vector128<uint>, Vector128<uint>) value = uintTable[i]; - var result = Sse2.Or(value.Item1, value.Item2); - uintTable.SetOutArray(result); - } - - for (int i = 0; i < testsCount; i++) - { - (Vector128<short>, Vector128<short>, Vector128<short>) value = shortTable[i]; - var result = Sse2.Or(value.Item1, value.Item2); - shortTable.SetOutArray(result); - } - - for (int i = 0; i < testsCount; i++) - { - (Vector128<ushort>, Vector128<ushort>, Vector128<ushort>) value = ushortTable[i]; - var result = Sse2.Or(value.Item1, value.Item2); - ushortTable.SetOutArray(result); - } - - for (int i = 0; i < testsCount; i++) - { - (Vector128<sbyte>, Vector128<sbyte>, Vector128<sbyte>) value = sbyteTable[i]; - var result = Sse2.Or(value.Item1, value.Item2); - sbyteTable.SetOutArray(result); - } - - for (int i = 0; i < testsCount; i++) - { - (Vector128<byte>, Vector128<byte>, Vector128<byte>) value = byteTable[i]; - var result = Sse2.Or(value.Item1, value.Item2); - byteTable.SetOutArray(result); - } - - CheckMethod<double> checkDouble = (double x, double y, double z, ref double a) => (a = BitwiseOr(x, y)) == z; - - if (!doubleTable.CheckResult(checkDouble)) - { - PrintError(doubleTable, methodUnderTestName, "(double x, double y, double z, ref double a) => (a = BitwiseOr(x, y)) == z", checkDouble); - testResult = Fail; - } - - CheckMethod<long> checkLong = (long x, long y, long z, ref long a) => (a = x | y) == z; - - if (!longTable.CheckResult(checkLong)) - { - PrintError(longTable, methodUnderTestName, "(long x, long y, long z, ref long a) => (a = x | y) == z", checkLong); - testResult = Fail; - } - - CheckMethod<ulong> checkUlong = (ulong x, ulong y, ulong z, ref ulong a) => (a = x | y) == z; - - if (!longTable.CheckResult(checkLong)) - { - PrintError(ulongTable, methodUnderTestName, "(ulong x, ulong y, ulong z, ref ulong a) => (a = x | y) == z", checkUlong); - testResult = Fail; - } - - CheckMethod<int> checkInt32 = (int x, int y, int z, ref int a) => (a = x | y) == z; - - if (!intTable.CheckResult(checkInt32)) - { - PrintError(intTable, methodUnderTestName, "(int x, int y, int z, ref int a) => (a = x | y) == z", checkInt32); - testResult = Fail; - } - - CheckMethod<uint> checkUInt32 = (uint x, uint y, uint z, ref uint a) => (a = x | y) == z; - - if (!uintTable.CheckResult(checkUInt32)) - { - PrintError(uintTable, methodUnderTestName, "(uint x, uint y, uint z, ref uint a) => (a = x | y) == z", checkUInt32); - testResult = Fail; - } - - CheckMethod<short> checkInt16 = (short x, short y, short z, ref short a) => (a = (short)(x | y)) == z; - - if (!shortTable.CheckResult(checkInt16)) - { - PrintError(shortTable, methodUnderTestName, "(short x, short y, short z, ref short a) => (a = (short)(x | y)) == z", checkInt16); - testResult = Fail; - } - - CheckMethod<ushort> checkUInt16 = (ushort x, ushort y, ushort z, ref ushort a) => (a = (ushort)(x | y)) == z; - - if (!ushortTable.CheckResult(checkUInt16)) - { - PrintError(ushortTable, methodUnderTestName, "(ushort x, ushort y, ushort z, ref ushort a) => (a = (ushort)(x | y)) == z", checkUInt16); - testResult = Fail; - } - - CheckMethod<sbyte> checkSByte = (sbyte x, sbyte y, sbyte z, ref sbyte a) => (a = (sbyte)(x | y)) == z; - - if (!sbyteTable.CheckResult(checkSByte)) - { - PrintError(sbyteTable, methodUnderTestName, "(sbyte x, sbyte y, sbyte z, ref sbyte a) => (a = (sbyte)(x | y)) == z", checkSByte); - testResult = Fail; - } - - CheckMethod<byte> checkByte = (byte x, byte y, byte z, ref byte a) => (a = (byte)(x | y)) == z; - - if (!byteTable.CheckResult(checkByte)) - { - PrintError(byteTable, methodUnderTestName, "(byte x, byte y, byte z, ref byte a) => (a = (byte)(x | y)) == z", checkByte); - testResult = Fail; - } - } - } - else - { - Console.WriteLine($"Sse2.IsSupported: {Sse2.IsSupported}, skipped tests of {typeof(Sse2)}.{methodUnderTestName}"); - } - - return testResult; - } - - public static unsafe double BitwiseOr(double x, double y) - { - var xUlong = BitConverter.ToUInt64(BitConverter.GetBytes(x)); - var yUlong = BitConverter.ToUInt64(BitConverter.GetBytes(y)); - var longAnd = xUlong | yUlong; - return BitConverter.ToDouble(BitConverter.GetBytes(longAnd)); - } - } -} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Or_r.csproj b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Or_r.csproj deleted file mode 100644 index d0be377c15..0000000000 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Or_r.csproj +++ /dev/null @@ -1,38 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" /> - <PropertyGroup> - <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> - <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> - <SchemaVersion>2.0</SchemaVersion> - <ProjectGuid>{44DBB8A7-5F29-4813-B2E3-7978EA45BED8}</ProjectGuid> - <OutputType>Exe</OutputType> - <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> - <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir> - <AllowUnsafeBlocks>true</AllowUnsafeBlocks> - </PropertyGroup> - <!-- Default configurations to help VS understand the configurations --> - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> - </PropertyGroup> - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' " /> - <ItemGroup> - <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies"> - <Visible>False</Visible> - </CodeAnalysisDependentAssemblyPaths> - </ItemGroup> - <PropertyGroup> - <DebugType>None</DebugType> - <Optimize> - </Optimize> - </PropertyGroup> - <ItemGroup> - <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" /> - </ItemGroup> - <ItemGroup> - <Compile Include="Or.cs" /> - <Compile Include="TestTableSse2.cs" /> - </ItemGroup> - <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" /> - <PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' "> - </PropertyGroup> -</Project>
\ No newline at end of file diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Or_ro.csproj b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Or_ro.csproj deleted file mode 100644 index abf2512272..0000000000 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Or_ro.csproj +++ /dev/null @@ -1,37 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" /> - <PropertyGroup> - <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> - <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> - <SchemaVersion>2.0</SchemaVersion> - <ProjectGuid>{3625F7C3-45E3-43A5-92B9-9028B9F9476B}</ProjectGuid> - <OutputType>Exe</OutputType> - <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> - <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir> - <AllowUnsafeBlocks>true</AllowUnsafeBlocks> - </PropertyGroup> - <!-- Default configurations to help VS understand the configurations --> - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> - </PropertyGroup> - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' " /> - <ItemGroup> - <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies"> - <Visible>False</Visible> - </CodeAnalysisDependentAssemblyPaths> - </ItemGroup> - <PropertyGroup> - <DebugType>None</DebugType> - <Optimize>True</Optimize> - </PropertyGroup> - <ItemGroup> - <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" /> - </ItemGroup> - <ItemGroup> - <Compile Include="Or.cs" /> - <Compile Include="TestTableSse2.cs" /> - </ItemGroup> - <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" /> - <PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' "> - </PropertyGroup> -</Project>
\ No newline at end of file diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Program.Sse2.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Program.Sse2.cs index 6994fe61da..768e3adf08 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Program.Sse2.cs +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Program.Sse2.cs @@ -21,6 +21,83 @@ namespace JIT.HardwareIntrinsics.X86 ["Add.UInt16"] = AddUInt16, ["Add.UInt32"] = AddUInt32, ["Add.UInt64"] = AddUInt64, + ["And.Double"] = AndDouble, + ["And.Byte"] = AndByte, + ["And.Int16"] = AndInt16, + ["And.Int32"] = AndInt32, + ["And.Int64"] = AndInt64, + ["And.SByte"] = AndSByte, + ["And.UInt16"] = AndUInt16, + ["And.UInt32"] = AndUInt32, + ["And.UInt64"] = AndUInt64, + ["AndNot.Double"] = AndNotDouble, + ["AndNot.Byte"] = AndNotByte, + ["AndNot.Int16"] = AndNotInt16, + ["AndNot.Int32"] = AndNotInt32, + ["AndNot.Int64"] = AndNotInt64, + ["AndNot.SByte"] = AndNotSByte, + ["AndNot.UInt16"] = AndNotUInt16, + ["AndNot.UInt32"] = AndNotUInt32, + ["AndNot.UInt64"] = AndNotUInt64, + ["CompareEqual.Double"] = CompareEqualDouble, + ["CompareEqual.Byte"] = CompareEqualByte, + ["CompareEqual.Int16"] = CompareEqualInt16, + ["CompareEqual.Int32"] = CompareEqualInt32, + ["CompareEqual.SByte"] = CompareEqualSByte, + ["CompareEqual.UInt16"] = CompareEqualUInt16, + ["CompareEqual.UInt32"] = CompareEqualUInt32, + ["CompareGreaterThan.Double"] = CompareGreaterThanDouble, + ["CompareGreaterThan.Int16"] = CompareGreaterThanInt16, + ["CompareGreaterThan.Int32"] = CompareGreaterThanInt32, + ["CompareGreaterThan.SByte"] = CompareGreaterThanSByte, + ["CompareGreaterThanOrEqual.Double"] = CompareGreaterThanOrEqualDouble, + ["CompareLessThan.Double"] = CompareLessThanDouble, + ["CompareLessThan.Int16"] = CompareLessThanInt16, + ["CompareLessThan.Int32"] = CompareLessThanInt32, + ["CompareLessThan.SByte"] = CompareLessThanSByte, + ["CompareLessThanOrEqual.Double"] = CompareLessThanOrEqualDouble, + ["CompareNotEqual.Double"] = CompareNotEqualDouble, + ["CompareNotGreaterThan.Double"] = CompareNotGreaterThanDouble, + ["CompareNotGreaterThanOrEqual.Double"] = CompareNotGreaterThanOrEqualDouble, + ["CompareNotLessThan.Double"] = CompareNotLessThanDouble, + ["CompareNotLessThanOrEqual.Double"] = CompareNotLessThanOrEqualDouble, + ["CompareOrdered.Double"] = CompareOrderedDouble, + ["CompareUnordered.Double"] = CompareUnorderedDouble, + ["Divide.Double"] = DivideDouble, + ["Max.Double"] = MaxDouble, + ["Max.Byte"] = MaxByte, + ["Max.Int16"] = MaxInt16, + ["Min.Double"] = MinDouble, + ["Min.Byte"] = MinByte, + ["Min.Int16"] = MinInt16, + ["Multiply.Double"] = MultiplyDouble, + ["Or.Double"] = OrDouble, + ["Or.Byte"] = OrByte, + ["Or.Int16"] = OrInt16, + ["Or.Int32"] = OrInt32, + ["Or.Int64"] = OrInt64, + ["Or.SByte"] = OrSByte, + ["Or.UInt16"] = OrUInt16, + ["Or.UInt32"] = OrUInt32, + ["Or.UInt64"] = OrUInt64, + ["Subtract.Double"] = SubtractDouble, + ["Subtract.Byte"] = SubtractByte, + ["Subtract.Int16"] = SubtractInt16, + ["Subtract.Int32"] = SubtractInt32, + ["Subtract.Int64"] = SubtractInt64, + ["Subtract.SByte"] = SubtractSByte, + ["Subtract.UInt16"] = SubtractUInt16, + ["Subtract.UInt32"] = SubtractUInt32, + ["Subtract.UInt64"] = SubtractUInt64, + ["Xor.Double"] = XorDouble, + ["Xor.Byte"] = XorByte, + ["Xor.Int16"] = XorInt16, + ["Xor.Int32"] = XorInt32, + ["Xor.Int64"] = XorInt64, + ["Xor.SByte"] = XorSByte, + ["Xor.UInt16"] = XorUInt16, + ["Xor.UInt32"] = XorUInt32, + ["Xor.UInt64"] = XorUInt64, }; } } diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Sse2_r.csproj b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Sse2_r.csproj index f25b4907e9..2711acf0dd 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Sse2_r.csproj +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Sse2_r.csproj @@ -27,8 +27,8 @@ <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" /> </ItemGroup> <ItemGroup> - <Compile Include="Add.Byte.cs" /> <Compile Include="Add.Double.cs" /> + <Compile Include="Add.Byte.cs" /> <Compile Include="Add.Int16.cs" /> <Compile Include="Add.Int32.cs" /> <Compile Include="Add.Int64.cs" /> @@ -36,9 +36,86 @@ <Compile Include="Add.UInt16.cs" /> <Compile Include="Add.UInt32.cs" /> <Compile Include="Add.UInt64.cs" /> + <Compile Include="And.Double.cs" /> + <Compile Include="And.Byte.cs" /> + <Compile Include="And.Int16.cs" /> + <Compile Include="And.Int32.cs" /> + <Compile Include="And.Int64.cs" /> + <Compile Include="And.SByte.cs" /> + <Compile Include="And.UInt16.cs" /> + <Compile Include="And.UInt32.cs" /> + <Compile Include="And.UInt64.cs" /> + <Compile Include="AndNot.Double.cs" /> + <Compile Include="AndNot.Byte.cs" /> + <Compile Include="AndNot.Int16.cs" /> + <Compile Include="AndNot.Int32.cs" /> + <Compile Include="AndNot.Int64.cs" /> + <Compile Include="AndNot.SByte.cs" /> + <Compile Include="AndNot.UInt16.cs" /> + <Compile Include="AndNot.UInt32.cs" /> + <Compile Include="AndNot.UInt64.cs" /> + <Compile Include="CompareEqual.Double.cs" /> + <Compile Include="CompareEqual.Byte.cs" /> + <Compile Include="CompareEqual.Int16.cs" /> + <Compile Include="CompareEqual.Int32.cs" /> + <Compile Include="CompareEqual.SByte.cs" /> + <Compile Include="CompareEqual.UInt16.cs" /> + <Compile Include="CompareEqual.UInt32.cs" /> + <Compile Include="CompareGreaterThan.Double.cs" /> + <Compile Include="CompareGreaterThan.Int16.cs" /> + <Compile Include="CompareGreaterThan.Int32.cs" /> + <Compile Include="CompareGreaterThan.SByte.cs" /> + <Compile Include="CompareGreaterThanOrEqual.Double.cs" /> + <Compile Include="CompareLessThan.Double.cs" /> + <Compile Include="CompareLessThan.Int16.cs" /> + <Compile Include="CompareLessThan.Int32.cs" /> + <Compile Include="CompareLessThan.SByte.cs" /> + <Compile Include="CompareLessThanOrEqual.Double.cs" /> + <Compile Include="CompareNotEqual.Double.cs" /> + <Compile Include="CompareNotGreaterThan.Double.cs" /> + <Compile Include="CompareNotGreaterThanOrEqual.Double.cs" /> + <Compile Include="CompareNotLessThan.Double.cs" /> + <Compile Include="CompareNotLessThanOrEqual.Double.cs" /> + <Compile Include="CompareOrdered.Double.cs" /> + <Compile Include="CompareUnordered.Double.cs" /> + <Compile Include="Divide.Double.cs" /> + <Compile Include="Max.Double.cs" /> + <Compile Include="Max.Byte.cs" /> + <Compile Include="Max.Int16.cs" /> + <Compile Include="Min.Double.cs" /> + <Compile Include="Min.Byte.cs" /> + <Compile Include="Min.Int16.cs" /> + <Compile Include="Multiply.Double.cs" /> + <Compile Include="Or.Double.cs" /> + <Compile Include="Or.Byte.cs" /> + <Compile Include="Or.Int16.cs" /> + <Compile Include="Or.Int32.cs" /> + <Compile Include="Or.Int64.cs" /> + <Compile Include="Or.SByte.cs" /> + <Compile Include="Or.UInt16.cs" /> + <Compile Include="Or.UInt32.cs" /> + <Compile Include="Or.UInt64.cs" /> + <Compile Include="Subtract.Double.cs" /> + <Compile Include="Subtract.Byte.cs" /> + <Compile Include="Subtract.Int16.cs" /> + <Compile Include="Subtract.Int32.cs" /> + <Compile Include="Subtract.Int64.cs" /> + <Compile Include="Subtract.SByte.cs" /> + <Compile Include="Subtract.UInt16.cs" /> + <Compile Include="Subtract.UInt32.cs" /> + <Compile Include="Subtract.UInt64.cs" /> + <Compile Include="Xor.Double.cs" /> + <Compile Include="Xor.Byte.cs" /> + <Compile Include="Xor.Int16.cs" /> + <Compile Include="Xor.Int32.cs" /> + <Compile Include="Xor.Int64.cs" /> + <Compile Include="Xor.SByte.cs" /> + <Compile Include="Xor.UInt16.cs" /> + <Compile Include="Xor.UInt32.cs" /> + <Compile Include="Xor.UInt64.cs" /> <Compile Include="Program.Sse2.cs" /> <Compile Include="..\Shared\Program.cs" /> - <Compile Include="..\Shared\SimpleBinOpTest_DataTable.cs" /> + <Compile Include="..\Shared\SimpleBinOpTest_DataTable_Aligned.cs" /> </ItemGroup> <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" /> <PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' "></PropertyGroup> diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Sse2_ro.csproj b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Sse2_ro.csproj index 003a20b285..2227b784b5 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Sse2_ro.csproj +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Sse2_ro.csproj @@ -27,8 +27,8 @@ <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" /> </ItemGroup> <ItemGroup> - <Compile Include="Add.Byte.cs" /> <Compile Include="Add.Double.cs" /> + <Compile Include="Add.Byte.cs" /> <Compile Include="Add.Int16.cs" /> <Compile Include="Add.Int32.cs" /> <Compile Include="Add.Int64.cs" /> @@ -36,9 +36,86 @@ <Compile Include="Add.UInt16.cs" /> <Compile Include="Add.UInt32.cs" /> <Compile Include="Add.UInt64.cs" /> + <Compile Include="And.Double.cs" /> + <Compile Include="And.Byte.cs" /> + <Compile Include="And.Int16.cs" /> + <Compile Include="And.Int32.cs" /> + <Compile Include="And.Int64.cs" /> + <Compile Include="And.SByte.cs" /> + <Compile Include="And.UInt16.cs" /> + <Compile Include="And.UInt32.cs" /> + <Compile Include="And.UInt64.cs" /> + <Compile Include="AndNot.Double.cs" /> + <Compile Include="AndNot.Byte.cs" /> + <Compile Include="AndNot.Int16.cs" /> + <Compile Include="AndNot.Int32.cs" /> + <Compile Include="AndNot.Int64.cs" /> + <Compile Include="AndNot.SByte.cs" /> + <Compile Include="AndNot.UInt16.cs" /> + <Compile Include="AndNot.UInt32.cs" /> + <Compile Include="AndNot.UInt64.cs" /> + <Compile Include="CompareEqual.Double.cs" /> + <Compile Include="CompareEqual.Byte.cs" /> + <Compile Include="CompareEqual.Int16.cs" /> + <Compile Include="CompareEqual.Int32.cs" /> + <Compile Include="CompareEqual.SByte.cs" /> + <Compile Include="CompareEqual.UInt16.cs" /> + <Compile Include="CompareEqual.UInt32.cs" /> + <Compile Include="CompareGreaterThan.Double.cs" /> + <Compile Include="CompareGreaterThan.Int16.cs" /> + <Compile Include="CompareGreaterThan.Int32.cs" /> + <Compile Include="CompareGreaterThan.SByte.cs" /> + <Compile Include="CompareGreaterThanOrEqual.Double.cs" /> + <Compile Include="CompareLessThan.Double.cs" /> + <Compile Include="CompareLessThan.Int16.cs" /> + <Compile Include="CompareLessThan.Int32.cs" /> + <Compile Include="CompareLessThan.SByte.cs" /> + <Compile Include="CompareLessThanOrEqual.Double.cs" /> + <Compile Include="CompareNotEqual.Double.cs" /> + <Compile Include="CompareNotGreaterThan.Double.cs" /> + <Compile Include="CompareNotGreaterThanOrEqual.Double.cs" /> + <Compile Include="CompareNotLessThan.Double.cs" /> + <Compile Include="CompareNotLessThanOrEqual.Double.cs" /> + <Compile Include="CompareOrdered.Double.cs" /> + <Compile Include="CompareUnordered.Double.cs" /> + <Compile Include="Divide.Double.cs" /> + <Compile Include="Max.Double.cs" /> + <Compile Include="Max.Byte.cs" /> + <Compile Include="Max.Int16.cs" /> + <Compile Include="Min.Double.cs" /> + <Compile Include="Min.Byte.cs" /> + <Compile Include="Min.Int16.cs" /> + <Compile Include="Multiply.Double.cs" /> + <Compile Include="Or.Double.cs" /> + <Compile Include="Or.Byte.cs" /> + <Compile Include="Or.Int16.cs" /> + <Compile Include="Or.Int32.cs" /> + <Compile Include="Or.Int64.cs" /> + <Compile Include="Or.SByte.cs" /> + <Compile Include="Or.UInt16.cs" /> + <Compile Include="Or.UInt32.cs" /> + <Compile Include="Or.UInt64.cs" /> + <Compile Include="Subtract.Double.cs" /> + <Compile Include="Subtract.Byte.cs" /> + <Compile Include="Subtract.Int16.cs" /> + <Compile Include="Subtract.Int32.cs" /> + <Compile Include="Subtract.Int64.cs" /> + <Compile Include="Subtract.SByte.cs" /> + <Compile Include="Subtract.UInt16.cs" /> + <Compile Include="Subtract.UInt32.cs" /> + <Compile Include="Subtract.UInt64.cs" /> + <Compile Include="Xor.Double.cs" /> + <Compile Include="Xor.Byte.cs" /> + <Compile Include="Xor.Int16.cs" /> + <Compile Include="Xor.Int32.cs" /> + <Compile Include="Xor.Int64.cs" /> + <Compile Include="Xor.SByte.cs" /> + <Compile Include="Xor.UInt16.cs" /> + <Compile Include="Xor.UInt32.cs" /> + <Compile Include="Xor.UInt64.cs" /> <Compile Include="Program.Sse2.cs" /> <Compile Include="..\Shared\Program.cs" /> - <Compile Include="..\Shared\SimpleBinOpTest_DataTable.cs" /> + <Compile Include="..\Shared\SimpleBinOpTest_DataTable_Aligned.cs" /> </ItemGroup> <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" /> <PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' "></PropertyGroup> diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Subtract.Byte.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Subtract.Byte.cs new file mode 100644 index 0000000000..dcd9ed39fe --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Subtract.Byte.cs @@ -0,0 +1,315 @@ +// 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 SubtractByte() + { + var test = new SimpleBinaryOpTest__SubtractByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + // 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(); + + // 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(); + + // 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 works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + 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__SubtractByte + { + private const int VectorSize = 16; + private const int ElementCount = VectorSize / sizeof(Byte); + + private static Byte[] _data1 = new Byte[ElementCount]; + private static Byte[] _data2 = new Byte[ElementCount]; + + private static Vector128<Byte> _clsVar1; + private static Vector128<Byte> _clsVar2; + + private Vector128<Byte> _fld1; + private Vector128<Byte> _fld2; + + private SimpleBinaryOpTest__DataTable<Byte> _dataTable; + + static SimpleBinaryOpTest__SubtractByte() + { + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (byte)(random.Next(0, byte.MaxValue)); _data2[i] = (byte)(random.Next(0, byte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Byte>, byte>(ref _clsVar1), ref Unsafe.As<Byte, byte>(ref _data2[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Byte>, byte>(ref _clsVar2), ref Unsafe.As<Byte, byte>(ref _data1[0]), VectorSize); + } + + public SimpleBinaryOpTest__SubtractByte() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (byte)(random.Next(0, byte.MaxValue)); _data2[i] = (byte)(random.Next(0, byte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Byte>, byte>(ref _fld1), ref Unsafe.As<Byte, byte>(ref _data1[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Byte>, byte>(ref _fld2), ref Unsafe.As<Byte, byte>(ref _data2[0]), VectorSize); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (byte)(random.Next(0, byte.MaxValue)); _data2[i] = (byte)(random.Next(0, byte.MaxValue)); } + _dataTable = new SimpleBinaryOpTest__DataTable<Byte>(_data1, _data2, new Byte[ElementCount], VectorSize); + } + + public bool IsSupported => Sse2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse2.Subtract( + Unsafe.Read<Vector128<Byte>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<Byte>>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse2.Subtract( + Sse2.LoadVector128((Byte*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Byte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse2.Subtract( + Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Subtract), new Type[] { typeof(Vector128<Byte>), typeof(Vector128<Byte>) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector128<Byte>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<Byte>>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Byte>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Subtract), new Type[] { typeof(Vector128<Byte>), typeof(Vector128<Byte>) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Byte*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Byte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Byte>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Subtract), new Type[] { typeof(Vector128<Byte>), typeof(Vector128<Byte>) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Byte>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse2.Subtract( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read<Vector128<Byte>>(_dataTable.inArray1Ptr); + var right = Unsafe.Read<Vector128<Byte>>(_dataTable.inArray2Ptr); + var result = Sse2.Subtract(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((Byte*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((Byte*)(_dataTable.inArray2Ptr)); + var result = Sse2.Subtract(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray2Ptr)); + var result = Sse2.Subtract(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__SubtractByte(); + var result = Sse2.Subtract(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse2.Subtract(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128<Byte> left, Vector128<Byte> right, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[ElementCount]; + Byte[] inArray2 = new Byte[ElementCount]; + Byte[] outArray = new Byte[ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Byte, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[ElementCount]; + Byte[] inArray2 = new Byte[ElementCount]; + Byte[] outArray = new Byte[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Byte, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Byte, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Byte, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Byte[] left, Byte[] right, Byte[] result, [CallerMemberName] string method = "") + { + if ((byte)(left[0] - right[0]) != result[0]) + { + Succeeded = false; + } + else + { + for (var i = 1; i < left.Length; i++) + { + if ((byte)(left[i] - right[i]) != result[i]) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Sse2)}.{nameof(Sse2.Subtract)}<Byte>: {method} failed:"); + Console.WriteLine($" left: ({string.Join(", ", left)})"); + Console.WriteLine($" right: ({string.Join(", ", right)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Subtract.Double.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Subtract.Double.cs new file mode 100644 index 0000000000..0e8c22da1d --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Subtract.Double.cs @@ -0,0 +1,315 @@ +// 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 SubtractDouble() + { + var test = new SimpleBinaryOpTest__SubtractDouble(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + // 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(); + + // 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(); + + // 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 works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + 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__SubtractDouble + { + private const int VectorSize = 16; + private const int ElementCount = VectorSize / sizeof(Double); + + private static Double[] _data1 = new Double[ElementCount]; + private static Double[] _data2 = new Double[ElementCount]; + + private static Vector128<Double> _clsVar1; + private static Vector128<Double> _clsVar2; + + private Vector128<Double> _fld1; + private Vector128<Double> _fld2; + + private SimpleBinaryOpTest__DataTable<Double> _dataTable; + + static SimpleBinaryOpTest__SubtractDouble() + { + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (double)(random.NextDouble()); _data2[i] = (double)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Double>, byte>(ref _clsVar1), ref Unsafe.As<Double, byte>(ref _data2[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Double>, byte>(ref _clsVar2), ref Unsafe.As<Double, byte>(ref _data1[0]), VectorSize); + } + + public SimpleBinaryOpTest__SubtractDouble() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (double)(random.NextDouble()); _data2[i] = (double)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Double>, byte>(ref _fld1), ref Unsafe.As<Double, byte>(ref _data1[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Double>, byte>(ref _fld2), ref Unsafe.As<Double, byte>(ref _data2[0]), VectorSize); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (double)(random.NextDouble()); _data2[i] = (double)(random.NextDouble()); } + _dataTable = new SimpleBinaryOpTest__DataTable<Double>(_data1, _data2, new Double[ElementCount], VectorSize); + } + + public bool IsSupported => Sse2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse2.Subtract( + Unsafe.Read<Vector128<Double>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<Double>>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse2.Subtract( + Sse2.LoadVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Double*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse2.Subtract( + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Subtract), new Type[] { typeof(Vector128<Double>), typeof(Vector128<Double>) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector128<Double>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<Double>>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Double>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Subtract), new Type[] { typeof(Vector128<Double>), typeof(Vector128<Double>) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Double*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Double>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Subtract), new Type[] { typeof(Vector128<Double>), typeof(Vector128<Double>) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Double>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse2.Subtract( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read<Vector128<Double>>(_dataTable.inArray1Ptr); + var right = Unsafe.Read<Vector128<Double>>(_dataTable.inArray2Ptr); + var result = Sse2.Subtract(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((Double*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((Double*)(_dataTable.inArray2Ptr)); + var result = Sse2.Subtract(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray2Ptr)); + var result = Sse2.Subtract(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__SubtractDouble(); + var result = Sse2.Subtract(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse2.Subtract(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128<Double> left, Vector128<Double> right, void* result, [CallerMemberName] string method = "") + { + Double[] inArray1 = new Double[ElementCount]; + Double[] inArray2 = new Double[ElementCount]; + Double[] outArray = new Double[ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Double[] inArray1 = new Double[ElementCount]; + Double[] inArray2 = new Double[ElementCount]; + Double[] outArray = new Double[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Double[] left, Double[] right, Double[] result, [CallerMemberName] string method = "") + { + if (BitConverter.DoubleToInt64Bits(left[0] - right[0]) != BitConverter.DoubleToInt64Bits(result[0])) + { + Succeeded = false; + } + else + { + for (var i = 1; i < left.Length; i++) + { + if (BitConverter.DoubleToInt64Bits(left[i] - right[i]) != BitConverter.DoubleToInt64Bits(result[i])) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Sse2)}.{nameof(Sse2.Subtract)}<Double>: {method} failed:"); + Console.WriteLine($" left: ({string.Join(", ", left)})"); + Console.WriteLine($" right: ({string.Join(", ", right)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Subtract.Int16.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Subtract.Int16.cs new file mode 100644 index 0000000000..737fd780f0 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Subtract.Int16.cs @@ -0,0 +1,315 @@ +// 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 SubtractInt16() + { + var test = new SimpleBinaryOpTest__SubtractInt16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + // 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(); + + // 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(); + + // 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 works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + 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__SubtractInt16 + { + private const int VectorSize = 16; + private const int ElementCount = VectorSize / sizeof(Int16); + + private static Int16[] _data1 = new Int16[ElementCount]; + private static Int16[] _data2 = new Int16[ElementCount]; + + private static Vector128<Int16> _clsVar1; + private static Vector128<Int16> _clsVar2; + + private Vector128<Int16> _fld1; + private Vector128<Int16> _fld2; + + private SimpleBinaryOpTest__DataTable<Int16> _dataTable; + + static SimpleBinaryOpTest__SubtractInt16() + { + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (short)(random.Next(short.MinValue, short.MaxValue)); _data2[i] = (short)(random.Next(short.MinValue, short.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int16>, byte>(ref _clsVar1), ref Unsafe.As<Int16, byte>(ref _data2[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int16>, byte>(ref _clsVar2), ref Unsafe.As<Int16, byte>(ref _data1[0]), VectorSize); + } + + public SimpleBinaryOpTest__SubtractInt16() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (short)(random.Next(short.MinValue, short.MaxValue)); _data2[i] = (short)(random.Next(short.MinValue, short.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int16>, byte>(ref _fld1), ref Unsafe.As<Int16, byte>(ref _data1[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int16>, byte>(ref _fld2), ref Unsafe.As<Int16, byte>(ref _data2[0]), VectorSize); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (short)(random.Next(short.MinValue, short.MaxValue)); _data2[i] = (short)(random.Next(short.MinValue, short.MaxValue)); } + _dataTable = new SimpleBinaryOpTest__DataTable<Int16>(_data1, _data2, new Int16[ElementCount], VectorSize); + } + + public bool IsSupported => Sse2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse2.Subtract( + Unsafe.Read<Vector128<Int16>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<Int16>>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse2.Subtract( + Sse2.LoadVector128((Int16*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Int16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse2.Subtract( + Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Subtract), new Type[] { typeof(Vector128<Int16>), typeof(Vector128<Int16>) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector128<Int16>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<Int16>>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Int16>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Subtract), new Type[] { typeof(Vector128<Int16>), typeof(Vector128<Int16>) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Int16*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Int16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Int16>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Subtract), new Type[] { typeof(Vector128<Int16>), typeof(Vector128<Int16>) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Int16>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse2.Subtract( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read<Vector128<Int16>>(_dataTable.inArray1Ptr); + var right = Unsafe.Read<Vector128<Int16>>(_dataTable.inArray2Ptr); + var result = Sse2.Subtract(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((Int16*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((Int16*)(_dataTable.inArray2Ptr)); + var result = Sse2.Subtract(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray2Ptr)); + var result = Sse2.Subtract(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__SubtractInt16(); + var result = Sse2.Subtract(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse2.Subtract(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128<Int16> left, Vector128<Int16> right, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[ElementCount]; + Int16[] inArray2 = new Int16[ElementCount]; + Int16[] outArray = new Int16[ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int16, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[ElementCount]; + Int16[] inArray2 = new Int16[ElementCount]; + Int16[] outArray = new Int16[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int16, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int16, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int16, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int16[] left, Int16[] right, Int16[] result, [CallerMemberName] string method = "") + { + if ((short)(left[0] - right[0]) != result[0]) + { + Succeeded = false; + } + else + { + for (var i = 1; i < left.Length; i++) + { + if ((short)(left[i] - right[i]) != result[i]) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Sse2)}.{nameof(Sse2.Subtract)}<Int16>: {method} failed:"); + Console.WriteLine($" left: ({string.Join(", ", left)})"); + Console.WriteLine($" right: ({string.Join(", ", right)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Subtract.Int32.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Subtract.Int32.cs new file mode 100644 index 0000000000..eb31b7ece7 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Subtract.Int32.cs @@ -0,0 +1,315 @@ +// 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 SubtractInt32() + { + var test = new SimpleBinaryOpTest__SubtractInt32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + // 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(); + + // 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(); + + // 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 works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + 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__SubtractInt32 + { + private const int VectorSize = 16; + private const int ElementCount = VectorSize / sizeof(Int32); + + private static Int32[] _data1 = new Int32[ElementCount]; + private static Int32[] _data2 = new Int32[ElementCount]; + + private static Vector128<Int32> _clsVar1; + private static Vector128<Int32> _clsVar2; + + private Vector128<Int32> _fld1; + private Vector128<Int32> _fld2; + + private SimpleBinaryOpTest__DataTable<Int32> _dataTable; + + static SimpleBinaryOpTest__SubtractInt32() + { + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (int)(random.Next(int.MinValue, int.MaxValue)); _data2[i] = (int)(random.Next(int.MinValue, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int32>, byte>(ref _clsVar1), ref Unsafe.As<Int32, byte>(ref _data2[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int32>, byte>(ref _clsVar2), ref Unsafe.As<Int32, byte>(ref _data1[0]), VectorSize); + } + + public SimpleBinaryOpTest__SubtractInt32() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (int)(random.Next(int.MinValue, int.MaxValue)); _data2[i] = (int)(random.Next(int.MinValue, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int32>, byte>(ref _fld1), ref Unsafe.As<Int32, byte>(ref _data1[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int32>, byte>(ref _fld2), ref Unsafe.As<Int32, byte>(ref _data2[0]), VectorSize); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (int)(random.Next(int.MinValue, int.MaxValue)); _data2[i] = (int)(random.Next(int.MinValue, int.MaxValue)); } + _dataTable = new SimpleBinaryOpTest__DataTable<Int32>(_data1, _data2, new Int32[ElementCount], VectorSize); + } + + public bool IsSupported => Sse2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse2.Subtract( + Unsafe.Read<Vector128<Int32>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<Int32>>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse2.Subtract( + Sse2.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Int32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse2.Subtract( + Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Subtract), new Type[] { typeof(Vector128<Int32>), typeof(Vector128<Int32>) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector128<Int32>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<Int32>>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Int32>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Subtract), new Type[] { typeof(Vector128<Int32>), typeof(Vector128<Int32>) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Int32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Int32>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Subtract), new Type[] { typeof(Vector128<Int32>), typeof(Vector128<Int32>) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Int32>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse2.Subtract( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read<Vector128<Int32>>(_dataTable.inArray1Ptr); + var right = Unsafe.Read<Vector128<Int32>>(_dataTable.inArray2Ptr); + var result = Sse2.Subtract(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((Int32*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((Int32*)(_dataTable.inArray2Ptr)); + var result = Sse2.Subtract(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray2Ptr)); + var result = Sse2.Subtract(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__SubtractInt32(); + var result = Sse2.Subtract(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse2.Subtract(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128<Int32> left, Vector128<Int32> right, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[ElementCount]; + Int32[] inArray2 = new Int32[ElementCount]; + Int32[] outArray = new Int32[ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int32, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[ElementCount]; + Int32[] inArray2 = new Int32[ElementCount]; + Int32[] outArray = new Int32[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int32, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int32, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int32, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int32[] left, Int32[] right, Int32[] result, [CallerMemberName] string method = "") + { + if ((int)(left[0] - right[0]) != result[0]) + { + Succeeded = false; + } + else + { + for (var i = 1; i < left.Length; i++) + { + if ((int)(left[i] - right[i]) != result[i]) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Sse2)}.{nameof(Sse2.Subtract)}<Int32>: {method} failed:"); + Console.WriteLine($" left: ({string.Join(", ", left)})"); + Console.WriteLine($" right: ({string.Join(", ", right)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Subtract.Int64.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Subtract.Int64.cs new file mode 100644 index 0000000000..f67c4f8604 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Subtract.Int64.cs @@ -0,0 +1,315 @@ +// 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 SubtractInt64() + { + var test = new SimpleBinaryOpTest__SubtractInt64(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + // 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(); + + // 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(); + + // 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 works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + 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__SubtractInt64 + { + private const int VectorSize = 16; + private const int ElementCount = VectorSize / sizeof(Int64); + + private static Int64[] _data1 = new Int64[ElementCount]; + private static Int64[] _data2 = new Int64[ElementCount]; + + private static Vector128<Int64> _clsVar1; + private static Vector128<Int64> _clsVar2; + + private Vector128<Int64> _fld1; + private Vector128<Int64> _fld2; + + private SimpleBinaryOpTest__DataTable<Int64> _dataTable; + + static SimpleBinaryOpTest__SubtractInt64() + { + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (long)(random.Next(int.MinValue, int.MaxValue)); _data2[i] = (long)(random.Next(int.MinValue, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int64>, byte>(ref _clsVar1), ref Unsafe.As<Int64, byte>(ref _data2[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int64>, byte>(ref _clsVar2), ref Unsafe.As<Int64, byte>(ref _data1[0]), VectorSize); + } + + public SimpleBinaryOpTest__SubtractInt64() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (long)(random.Next(int.MinValue, int.MaxValue)); _data2[i] = (long)(random.Next(int.MinValue, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int64>, byte>(ref _fld1), ref Unsafe.As<Int64, byte>(ref _data1[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int64>, byte>(ref _fld2), ref Unsafe.As<Int64, byte>(ref _data2[0]), VectorSize); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (long)(random.Next(int.MinValue, int.MaxValue)); _data2[i] = (long)(random.Next(int.MinValue, int.MaxValue)); } + _dataTable = new SimpleBinaryOpTest__DataTable<Int64>(_data1, _data2, new Int64[ElementCount], VectorSize); + } + + public bool IsSupported => Sse2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse2.Subtract( + Unsafe.Read<Vector128<Int64>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<Int64>>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse2.Subtract( + Sse2.LoadVector128((Int64*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Int64*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse2.Subtract( + Sse2.LoadAlignedVector128((Int64*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Int64*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Subtract), new Type[] { typeof(Vector128<Int64>), typeof(Vector128<Int64>) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector128<Int64>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<Int64>>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Int64>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Subtract), new Type[] { typeof(Vector128<Int64>), typeof(Vector128<Int64>) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Int64*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Int64*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Int64>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Subtract), new Type[] { typeof(Vector128<Int64>), typeof(Vector128<Int64>) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Int64*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Int64*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Int64>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse2.Subtract( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read<Vector128<Int64>>(_dataTable.inArray1Ptr); + var right = Unsafe.Read<Vector128<Int64>>(_dataTable.inArray2Ptr); + var result = Sse2.Subtract(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((Int64*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((Int64*)(_dataTable.inArray2Ptr)); + var result = Sse2.Subtract(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((Int64*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((Int64*)(_dataTable.inArray2Ptr)); + var result = Sse2.Subtract(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__SubtractInt64(); + var result = Sse2.Subtract(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse2.Subtract(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128<Int64> left, Vector128<Int64> right, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[ElementCount]; + Int64[] inArray2 = new Int64[ElementCount]; + Int64[] outArray = new Int64[ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int64, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[ElementCount]; + Int64[] inArray2 = new Int64[ElementCount]; + Int64[] outArray = new Int64[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int64, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int64, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int64, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int64[] left, Int64[] right, Int64[] result, [CallerMemberName] string method = "") + { + if ((long)(left[0] - right[0]) != result[0]) + { + Succeeded = false; + } + else + { + for (var i = 1; i < left.Length; i++) + { + if ((long)(left[i] - right[i]) != result[i]) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Sse2)}.{nameof(Sse2.Subtract)}<Int64>: {method} failed:"); + Console.WriteLine($" left: ({string.Join(", ", left)})"); + Console.WriteLine($" right: ({string.Join(", ", right)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Subtract.SByte.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Subtract.SByte.cs new file mode 100644 index 0000000000..c3fe70cbd6 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Subtract.SByte.cs @@ -0,0 +1,315 @@ +// 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 SubtractSByte() + { + var test = new SimpleBinaryOpTest__SubtractSByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + // 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(); + + // 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(); + + // 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 works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + 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__SubtractSByte + { + private const int VectorSize = 16; + private const int ElementCount = VectorSize / sizeof(SByte); + + private static SByte[] _data1 = new SByte[ElementCount]; + private static SByte[] _data2 = new SByte[ElementCount]; + + private static Vector128<SByte> _clsVar1; + private static Vector128<SByte> _clsVar2; + + private Vector128<SByte> _fld1; + private Vector128<SByte> _fld2; + + private SimpleBinaryOpTest__DataTable<SByte> _dataTable; + + static SimpleBinaryOpTest__SubtractSByte() + { + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue)); _data2[i] = (sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<SByte>, byte>(ref _clsVar1), ref Unsafe.As<SByte, byte>(ref _data2[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<SByte>, byte>(ref _clsVar2), ref Unsafe.As<SByte, byte>(ref _data1[0]), VectorSize); + } + + public SimpleBinaryOpTest__SubtractSByte() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue)); _data2[i] = (sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<SByte>, byte>(ref _fld1), ref Unsafe.As<SByte, byte>(ref _data1[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<SByte>, byte>(ref _fld2), ref Unsafe.As<SByte, byte>(ref _data2[0]), VectorSize); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue)); _data2[i] = (sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue)); } + _dataTable = new SimpleBinaryOpTest__DataTable<SByte>(_data1, _data2, new SByte[ElementCount], VectorSize); + } + + public bool IsSupported => Sse2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse2.Subtract( + Unsafe.Read<Vector128<SByte>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<SByte>>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse2.Subtract( + Sse2.LoadVector128((SByte*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((SByte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse2.Subtract( + Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Subtract), new Type[] { typeof(Vector128<SByte>), typeof(Vector128<SByte>) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector128<SByte>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<SByte>>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<SByte>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Subtract), new Type[] { typeof(Vector128<SByte>), typeof(Vector128<SByte>) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((SByte*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((SByte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<SByte>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Subtract), new Type[] { typeof(Vector128<SByte>), typeof(Vector128<SByte>) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<SByte>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse2.Subtract( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read<Vector128<SByte>>(_dataTable.inArray1Ptr); + var right = Unsafe.Read<Vector128<SByte>>(_dataTable.inArray2Ptr); + var result = Sse2.Subtract(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((SByte*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((SByte*)(_dataTable.inArray2Ptr)); + var result = Sse2.Subtract(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArray2Ptr)); + var result = Sse2.Subtract(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__SubtractSByte(); + var result = Sse2.Subtract(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse2.Subtract(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128<SByte> left, Vector128<SByte> right, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[ElementCount]; + SByte[] inArray2 = new SByte[ElementCount]; + SByte[] outArray = new SByte[ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<SByte, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[ElementCount]; + SByte[] inArray2 = new SByte[ElementCount]; + SByte[] outArray = new SByte[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<SByte, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<SByte, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<SByte, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(SByte[] left, SByte[] right, SByte[] result, [CallerMemberName] string method = "") + { + if ((sbyte)(left[0] - right[0]) != result[0]) + { + Succeeded = false; + } + else + { + for (var i = 1; i < left.Length; i++) + { + if ((sbyte)(left[i] - right[i]) != result[i]) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Sse2)}.{nameof(Sse2.Subtract)}<SByte>: {method} failed:"); + Console.WriteLine($" left: ({string.Join(", ", left)})"); + Console.WriteLine($" right: ({string.Join(", ", right)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Subtract.UInt16.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Subtract.UInt16.cs new file mode 100644 index 0000000000..3ac3c7ff46 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Subtract.UInt16.cs @@ -0,0 +1,315 @@ +// 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 SubtractUInt16() + { + var test = new SimpleBinaryOpTest__SubtractUInt16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + // 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(); + + // 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(); + + // 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 works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + 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__SubtractUInt16 + { + private const int VectorSize = 16; + private const int ElementCount = VectorSize / sizeof(UInt16); + + private static UInt16[] _data1 = new UInt16[ElementCount]; + private static UInt16[] _data2 = new UInt16[ElementCount]; + + private static Vector128<UInt16> _clsVar1; + private static Vector128<UInt16> _clsVar2; + + private Vector128<UInt16> _fld1; + private Vector128<UInt16> _fld2; + + private SimpleBinaryOpTest__DataTable<UInt16> _dataTable; + + static SimpleBinaryOpTest__SubtractUInt16() + { + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (ushort)(random.Next(0, ushort.MaxValue)); _data2[i] = (ushort)(random.Next(0, ushort.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt16>, byte>(ref _clsVar1), ref Unsafe.As<UInt16, byte>(ref _data2[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt16>, byte>(ref _clsVar2), ref Unsafe.As<UInt16, byte>(ref _data1[0]), VectorSize); + } + + public SimpleBinaryOpTest__SubtractUInt16() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (ushort)(random.Next(0, ushort.MaxValue)); _data2[i] = (ushort)(random.Next(0, ushort.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt16>, byte>(ref _fld1), ref Unsafe.As<UInt16, byte>(ref _data1[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt16>, byte>(ref _fld2), ref Unsafe.As<UInt16, byte>(ref _data2[0]), VectorSize); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (ushort)(random.Next(0, ushort.MaxValue)); _data2[i] = (ushort)(random.Next(0, ushort.MaxValue)); } + _dataTable = new SimpleBinaryOpTest__DataTable<UInt16>(_data1, _data2, new UInt16[ElementCount], VectorSize); + } + + public bool IsSupported => Sse2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse2.Subtract( + Unsafe.Read<Vector128<UInt16>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<UInt16>>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse2.Subtract( + Sse2.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse2.Subtract( + Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Subtract), new Type[] { typeof(Vector128<UInt16>), typeof(Vector128<UInt16>) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector128<UInt16>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<UInt16>>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<UInt16>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Subtract), new Type[] { typeof(Vector128<UInt16>), typeof(Vector128<UInt16>) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<UInt16>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Subtract), new Type[] { typeof(Vector128<UInt16>), typeof(Vector128<UInt16>) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<UInt16>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse2.Subtract( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read<Vector128<UInt16>>(_dataTable.inArray1Ptr); + var right = Unsafe.Read<Vector128<UInt16>>(_dataTable.inArray2Ptr); + var result = Sse2.Subtract(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)); + var result = Sse2.Subtract(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArray2Ptr)); + var result = Sse2.Subtract(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__SubtractUInt16(); + var result = Sse2.Subtract(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse2.Subtract(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128<UInt16> left, Vector128<UInt16> right, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[ElementCount]; + UInt16[] inArray2 = new UInt16[ElementCount]; + UInt16[] outArray = new UInt16[ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt16, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[ElementCount]; + UInt16[] inArray2 = new UInt16[ElementCount]; + UInt16[] outArray = new UInt16[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt16, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt16, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt16, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt16[] left, UInt16[] right, UInt16[] result, [CallerMemberName] string method = "") + { + if ((ushort)(left[0] - right[0]) != result[0]) + { + Succeeded = false; + } + else + { + for (var i = 1; i < left.Length; i++) + { + if ((ushort)(left[i] - right[i]) != result[i]) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Sse2)}.{nameof(Sse2.Subtract)}<UInt16>: {method} failed:"); + Console.WriteLine($" left: ({string.Join(", ", left)})"); + Console.WriteLine($" right: ({string.Join(", ", right)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Subtract.UInt32.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Subtract.UInt32.cs new file mode 100644 index 0000000000..dd4ead9740 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Subtract.UInt32.cs @@ -0,0 +1,315 @@ +// 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 SubtractUInt32() + { + var test = new SimpleBinaryOpTest__SubtractUInt32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + // 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(); + + // 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(); + + // 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 works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + 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__SubtractUInt32 + { + private const int VectorSize = 16; + private const int ElementCount = VectorSize / sizeof(UInt32); + + private static UInt32[] _data1 = new UInt32[ElementCount]; + private static UInt32[] _data2 = new UInt32[ElementCount]; + + private static Vector128<UInt32> _clsVar1; + private static Vector128<UInt32> _clsVar2; + + private Vector128<UInt32> _fld1; + private Vector128<UInt32> _fld2; + + private SimpleBinaryOpTest__DataTable<UInt32> _dataTable; + + static SimpleBinaryOpTest__SubtractUInt32() + { + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (uint)(random.Next(0, int.MaxValue)); _data2[i] = (uint)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt32>, byte>(ref _clsVar1), ref Unsafe.As<UInt32, byte>(ref _data2[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt32>, byte>(ref _clsVar2), ref Unsafe.As<UInt32, byte>(ref _data1[0]), VectorSize); + } + + public SimpleBinaryOpTest__SubtractUInt32() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (uint)(random.Next(0, int.MaxValue)); _data2[i] = (uint)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt32>, byte>(ref _fld1), ref Unsafe.As<UInt32, byte>(ref _data1[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt32>, byte>(ref _fld2), ref Unsafe.As<UInt32, byte>(ref _data2[0]), VectorSize); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (uint)(random.Next(0, int.MaxValue)); _data2[i] = (uint)(random.Next(0, int.MaxValue)); } + _dataTable = new SimpleBinaryOpTest__DataTable<UInt32>(_data1, _data2, new UInt32[ElementCount], VectorSize); + } + + public bool IsSupported => Sse2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse2.Subtract( + Unsafe.Read<Vector128<UInt32>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<UInt32>>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse2.Subtract( + Sse2.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse2.Subtract( + Sse2.LoadAlignedVector128((UInt32*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((UInt32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Subtract), new Type[] { typeof(Vector128<UInt32>), typeof(Vector128<UInt32>) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector128<UInt32>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<UInt32>>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<UInt32>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Subtract), new Type[] { typeof(Vector128<UInt32>), typeof(Vector128<UInt32>) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<UInt32>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Subtract), new Type[] { typeof(Vector128<UInt32>), typeof(Vector128<UInt32>) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((UInt32*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((UInt32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<UInt32>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse2.Subtract( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read<Vector128<UInt32>>(_dataTable.inArray1Ptr); + var right = Unsafe.Read<Vector128<UInt32>>(_dataTable.inArray2Ptr); + var result = Sse2.Subtract(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)); + var result = Sse2.Subtract(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((UInt32*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((UInt32*)(_dataTable.inArray2Ptr)); + var result = Sse2.Subtract(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__SubtractUInt32(); + var result = Sse2.Subtract(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse2.Subtract(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128<UInt32> left, Vector128<UInt32> right, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[ElementCount]; + UInt32[] inArray2 = new UInt32[ElementCount]; + UInt32[] outArray = new UInt32[ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt32, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[ElementCount]; + UInt32[] inArray2 = new UInt32[ElementCount]; + UInt32[] outArray = new UInt32[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt32, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt32, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt32, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt32[] left, UInt32[] right, UInt32[] result, [CallerMemberName] string method = "") + { + if ((uint)(left[0] - right[0]) != result[0]) + { + Succeeded = false; + } + else + { + for (var i = 1; i < left.Length; i++) + { + if ((uint)(left[i] - right[i]) != result[i]) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Sse2)}.{nameof(Sse2.Subtract)}<UInt32>: {method} failed:"); + Console.WriteLine($" left: ({string.Join(", ", left)})"); + Console.WriteLine($" right: ({string.Join(", ", right)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Subtract.UInt64.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Subtract.UInt64.cs new file mode 100644 index 0000000000..992fe56faa --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Subtract.UInt64.cs @@ -0,0 +1,315 @@ +// 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 SubtractUInt64() + { + var test = new SimpleBinaryOpTest__SubtractUInt64(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + // 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(); + + // 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(); + + // 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 works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + 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__SubtractUInt64 + { + private const int VectorSize = 16; + private const int ElementCount = VectorSize / sizeof(UInt64); + + private static UInt64[] _data1 = new UInt64[ElementCount]; + private static UInt64[] _data2 = new UInt64[ElementCount]; + + private static Vector128<UInt64> _clsVar1; + private static Vector128<UInt64> _clsVar2; + + private Vector128<UInt64> _fld1; + private Vector128<UInt64> _fld2; + + private SimpleBinaryOpTest__DataTable<UInt64> _dataTable; + + static SimpleBinaryOpTest__SubtractUInt64() + { + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (ulong)(random.Next(0, int.MaxValue)); _data2[i] = (ulong)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt64>, byte>(ref _clsVar1), ref Unsafe.As<UInt64, byte>(ref _data2[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt64>, byte>(ref _clsVar2), ref Unsafe.As<UInt64, byte>(ref _data1[0]), VectorSize); + } + + public SimpleBinaryOpTest__SubtractUInt64() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (ulong)(random.Next(0, int.MaxValue)); _data2[i] = (ulong)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt64>, byte>(ref _fld1), ref Unsafe.As<UInt64, byte>(ref _data1[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt64>, byte>(ref _fld2), ref Unsafe.As<UInt64, byte>(ref _data2[0]), VectorSize); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (ulong)(random.Next(0, int.MaxValue)); _data2[i] = (ulong)(random.Next(0, int.MaxValue)); } + _dataTable = new SimpleBinaryOpTest__DataTable<UInt64>(_data1, _data2, new UInt64[ElementCount], VectorSize); + } + + public bool IsSupported => Sse2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse2.Subtract( + Unsafe.Read<Vector128<UInt64>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<UInt64>>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse2.Subtract( + Sse2.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((UInt64*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse2.Subtract( + Sse2.LoadAlignedVector128((UInt64*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((UInt64*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Subtract), new Type[] { typeof(Vector128<UInt64>), typeof(Vector128<UInt64>) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector128<UInt64>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<UInt64>>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<UInt64>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Subtract), new Type[] { typeof(Vector128<UInt64>), typeof(Vector128<UInt64>) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((UInt64*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<UInt64>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Subtract), new Type[] { typeof(Vector128<UInt64>), typeof(Vector128<UInt64>) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((UInt64*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((UInt64*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<UInt64>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse2.Subtract( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read<Vector128<UInt64>>(_dataTable.inArray1Ptr); + var right = Unsafe.Read<Vector128<UInt64>>(_dataTable.inArray2Ptr); + var result = Sse2.Subtract(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((UInt64*)(_dataTable.inArray2Ptr)); + var result = Sse2.Subtract(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((UInt64*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((UInt64*)(_dataTable.inArray2Ptr)); + var result = Sse2.Subtract(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__SubtractUInt64(); + var result = Sse2.Subtract(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse2.Subtract(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128<UInt64> left, Vector128<UInt64> right, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray1 = new UInt64[ElementCount]; + UInt64[] inArray2 = new UInt64[ElementCount]; + UInt64[] outArray = new UInt64[ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt64, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray1 = new UInt64[ElementCount]; + UInt64[] inArray2 = new UInt64[ElementCount]; + UInt64[] outArray = new UInt64[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt64, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt64, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt64, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt64[] left, UInt64[] right, UInt64[] result, [CallerMemberName] string method = "") + { + if ((ulong)(left[0] - right[0]) != result[0]) + { + Succeeded = false; + } + else + { + for (var i = 1; i < left.Length; i++) + { + if ((ulong)(left[i] - right[i]) != result[i]) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Sse2)}.{nameof(Sse2.Subtract)}<UInt64>: {method} failed:"); + Console.WriteLine($" left: ({string.Join(", ", left)})"); + Console.WriteLine($" right: ({string.Join(", ", right)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Subtract.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Subtract.cs deleted file mode 100644 index ce786d6df8..0000000000 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Subtract.cs +++ /dev/null @@ -1,179 +0,0 @@ -// 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. -// - -using System; -using System.Runtime.Intrinsics; -using System.Runtime.Intrinsics.X86; - -namespace IntelHardwareIntrinsicTest -{ - internal static partial class Program - { - const int Pass = 100; - const int Fail = 0; - - static unsafe int Main(string[] args) - { - int testResult = Pass; - int testsCount = 21; - string methodUnderTestName = nameof(Sse2.Subtract); - - if (Sse2.IsSupported) - { - using (var doubleTable = TestTableSse2<double>.Create(testsCount)) - using (var longTable = TestTableSse2<long>.Create(testsCount)) - using (var ulongTable = TestTableSse2<ulong>.Create(testsCount)) - using (var intTable = TestTableSse2<int>.Create(testsCount)) - using (var uintTable = TestTableSse2<uint>.Create(testsCount)) - using (var shortTable = TestTableSse2<short>.Create(testsCount)) - using (var ushortTable = TestTableSse2<ushort>.Create(testsCount)) - using (var sbyteTable = TestTableSse2<sbyte>.Create(testsCount)) - using (var byteTable = TestTableSse2<byte>.Create(testsCount)) - { - for (int i = 0; i < testsCount; i++) - { - (Vector128<double>, Vector128<double>, Vector128<double>) value = doubleTable[i]; - var result = Sse2.Subtract(value.Item1, value.Item2); - doubleTable.SetOutArray(result); - } - - for (int i = 0; i < testsCount; i++) - { - (Vector128<long>, Vector128<long>, Vector128<long>) value = longTable[i]; - var result = Sse2.Subtract(value.Item1, value.Item2); - longTable.SetOutArray(result); - } - - for (int i = 0; i < testsCount; i++) - { - (Vector128<ulong>, Vector128<ulong>, Vector128<ulong>) value = ulongTable[i]; - var result = Sse2.Subtract(value.Item1, value.Item2); - ulongTable.SetOutArray(result); - } - - for (int i = 0; i < testsCount; i++) - { - (Vector128<int>, Vector128<int>, Vector128<int>) value = intTable[i]; - var result = Sse2.Subtract(value.Item1, value.Item2); - intTable.SetOutArray(result); - } - - for (int i = 0; i < testsCount; i++) - { - (Vector128<uint>, Vector128<uint>, Vector128<uint>) value = uintTable[i]; - var result = Sse2.Subtract(value.Item1, value.Item2); - uintTable.SetOutArray(result); - } - - for (int i = 0; i < testsCount; i++) - { - (Vector128<short>, Vector128<short>, Vector128<short>) value = shortTable[i]; - var result = Sse2.Subtract(value.Item1, value.Item2); - shortTable.SetOutArray(result); - } - - for (int i = 0; i < testsCount; i++) - { - (Vector128<ushort>, Vector128<ushort>, Vector128<ushort>) value = ushortTable[i]; - var result = Sse2.Subtract(value.Item1, value.Item2); - ushortTable.SetOutArray(result); - } - - for (int i = 0; i < testsCount; i++) - { - (Vector128<sbyte>, Vector128<sbyte>, Vector128<sbyte>) value = sbyteTable[i]; - var result = Sse2.Subtract(value.Item1, value.Item2); - sbyteTable.SetOutArray(result); - } - - for (int i = 0; i < testsCount; i++) - { - (Vector128<byte>, Vector128<byte>, Vector128<byte>) value = byteTable[i]; - var result = Sse2.Subtract(value.Item1, value.Item2); - byteTable.SetOutArray(result); - } - - CheckMethod<double> checkDouble = (double x, double y, double z, ref double a) => (a = x - y) == z; - - if (!doubleTable.CheckResult(checkDouble)) - { - PrintError(doubleTable, methodUnderTestName, "(double x, double y, double z, ref double a) => (a = x - y) == z", checkDouble); - testResult = Fail; - } - - CheckMethod<long> checkLong = (long x, long y, long z, ref long a) => (a = x - y) == z; - - if (!longTable.CheckResult(checkLong)) - { - PrintError(longTable, methodUnderTestName, "(long x, long y, long z, ref long a) => (a = x - y) == z", checkLong); - testResult = Fail; - } - - CheckMethod<ulong> checkUlong = (ulong x, ulong y, ulong z, ref ulong a) => (a = x - y) == z; - - if (!longTable.CheckResult(checkLong)) - { - PrintError(ulongTable, methodUnderTestName, "(ulong x, ulong y, ulong z, ref ulong a) => (a = x - y) == z", checkUlong); - testResult = Fail; - } - - CheckMethod<int> checkInt32 = (int x, int y, int z, ref int a) => (a = x - y) == z; - - if (!intTable.CheckResult(checkInt32)) - { - PrintError(intTable, methodUnderTestName, "(int x, int y, int z, ref int a) => (a = x - y) == z", checkInt32); - testResult = Fail; - } - - CheckMethod<uint> checkUInt32 = (uint x, uint y, uint z, ref uint a) => (a = x - y) == z; - - if (!uintTable.CheckResult(checkUInt32)) - { - PrintError(uintTable, methodUnderTestName, "(uint x, uint y, uint z, ref uint a) => (a = x - y) == z", checkUInt32); - testResult = Fail; - } - - CheckMethod<short> checkInt16 = (short x, short y, short z, ref short a) => (a = (short)(x - y)) == z; - - if (!shortTable.CheckResult(checkInt16)) - { - PrintError(shortTable, methodUnderTestName, "(short x, short y, short z, ref short a) => (a = (short)(x - y)) == z", checkInt16); - testResult = Fail; - } - - CheckMethod<ushort> checkUInt16 = (ushort x, ushort y, ushort z, ref ushort a) => (a = (ushort)(x - y)) == z; - - if (!ushortTable.CheckResult(checkUInt16)) - { - PrintError(ushortTable, methodUnderTestName, "(ushort x, ushort y, ushort z, ref ushort a) => (a = (ushort)(x - y)) == z", checkUInt16); - testResult = Fail; - } - - CheckMethod<sbyte> checkSByte = (sbyte x, sbyte y, sbyte z, ref sbyte a) => (a = (sbyte)(x - y)) == z; - - if (!sbyteTable.CheckResult(checkSByte)) - { - PrintError(sbyteTable, methodUnderTestName, "(sbyte x, sbyte y, sbyte z, ref sbyte a) => (a = (sbyte)(x - y)) == z", checkSByte); - testResult = Fail; - } - - CheckMethod<byte> checkByte = (byte x, byte y, byte z, ref byte a) => (a = (byte)(x - y)) == z; - - if (!byteTable.CheckResult(checkByte)) - { - PrintError(byteTable, methodUnderTestName, "(byte x, byte y, byte z, ref byte a) => (a = (byte)(x - y)) == z", checkByte); - testResult = Fail; - } - } - } - else - { - Console.WriteLine($"Sse2.IsSupported: {Sse2.IsSupported}, skipped tests of {typeof(Sse2)}.{methodUnderTestName}"); - } - - return testResult; - } - } -} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Subtract_r.csproj b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Subtract_r.csproj deleted file mode 100644 index accd716b36..0000000000 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Subtract_r.csproj +++ /dev/null @@ -1,38 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" /> - <PropertyGroup> - <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> - <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> - <SchemaVersion>2.0</SchemaVersion> - <ProjectGuid>{DDE1DDD6-B6BD-42D2-9D49-5BCE2E707442}</ProjectGuid> - <OutputType>Exe</OutputType> - <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> - <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir> - <AllowUnsafeBlocks>true</AllowUnsafeBlocks> - </PropertyGroup> - <!-- Default configurations to help VS understand the configurations --> - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> - </PropertyGroup> - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' " /> - <ItemGroup> - <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies"> - <Visible>False</Visible> - </CodeAnalysisDependentAssemblyPaths> - </ItemGroup> - <PropertyGroup> - <DebugType>None</DebugType> - <Optimize> - </Optimize> - </PropertyGroup> - <ItemGroup> - <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" /> - </ItemGroup> - <ItemGroup> - <Compile Include="Subtract.cs" /> - <Compile Include="TestTableSse2.cs" /> - </ItemGroup> - <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" /> - <PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' "> - </PropertyGroup> -</Project>
\ No newline at end of file diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Subtract_ro.csproj b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Subtract_ro.csproj deleted file mode 100644 index 810f23330d..0000000000 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Subtract_ro.csproj +++ /dev/null @@ -1,37 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" /> - <PropertyGroup> - <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> - <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> - <SchemaVersion>2.0</SchemaVersion> - <ProjectGuid>{7B7FCE02-0D75-4BE2-80C0-29F2D410FDF3}</ProjectGuid> - <OutputType>Exe</OutputType> - <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> - <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir> - <AllowUnsafeBlocks>true</AllowUnsafeBlocks> - </PropertyGroup> - <!-- Default configurations to help VS understand the configurations --> - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> - </PropertyGroup> - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' " /> - <ItemGroup> - <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies"> - <Visible>False</Visible> - </CodeAnalysisDependentAssemblyPaths> - </ItemGroup> - <PropertyGroup> - <DebugType>None</DebugType> - <Optimize>True</Optimize> - </PropertyGroup> - <ItemGroup> - <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" /> - </ItemGroup> - <ItemGroup> - <Compile Include="Subtract.cs" /> - <Compile Include="TestTableSse2.cs" /> - </ItemGroup> - <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" /> - <PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' "> - </PropertyGroup> -</Project>
\ No newline at end of file diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Xor.Byte.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Xor.Byte.cs new file mode 100644 index 0000000000..6d8ad708ba --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Xor.Byte.cs @@ -0,0 +1,315 @@ +// 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 XorByte() + { + var test = new SimpleBinaryOpTest__XorByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + // 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(); + + // 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(); + + // 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 works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + 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__XorByte + { + private const int VectorSize = 16; + private const int ElementCount = VectorSize / sizeof(Byte); + + private static Byte[] _data1 = new Byte[ElementCount]; + private static Byte[] _data2 = new Byte[ElementCount]; + + private static Vector128<Byte> _clsVar1; + private static Vector128<Byte> _clsVar2; + + private Vector128<Byte> _fld1; + private Vector128<Byte> _fld2; + + private SimpleBinaryOpTest__DataTable<Byte> _dataTable; + + static SimpleBinaryOpTest__XorByte() + { + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (byte)(random.Next(0, byte.MaxValue)); _data2[i] = (byte)(random.Next(0, byte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Byte>, byte>(ref _clsVar1), ref Unsafe.As<Byte, byte>(ref _data2[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Byte>, byte>(ref _clsVar2), ref Unsafe.As<Byte, byte>(ref _data1[0]), VectorSize); + } + + public SimpleBinaryOpTest__XorByte() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (byte)(random.Next(0, byte.MaxValue)); _data2[i] = (byte)(random.Next(0, byte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Byte>, byte>(ref _fld1), ref Unsafe.As<Byte, byte>(ref _data1[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Byte>, byte>(ref _fld2), ref Unsafe.As<Byte, byte>(ref _data2[0]), VectorSize); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (byte)(random.Next(0, byte.MaxValue)); _data2[i] = (byte)(random.Next(0, byte.MaxValue)); } + _dataTable = new SimpleBinaryOpTest__DataTable<Byte>(_data1, _data2, new Byte[ElementCount], VectorSize); + } + + public bool IsSupported => Sse2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse2.Xor( + Unsafe.Read<Vector128<Byte>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<Byte>>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse2.Xor( + Sse2.LoadVector128((Byte*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Byte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse2.Xor( + Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Xor), new Type[] { typeof(Vector128<Byte>), typeof(Vector128<Byte>) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector128<Byte>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<Byte>>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Byte>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Xor), new Type[] { typeof(Vector128<Byte>), typeof(Vector128<Byte>) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Byte*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Byte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Byte>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Xor), new Type[] { typeof(Vector128<Byte>), typeof(Vector128<Byte>) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Byte>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse2.Xor( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read<Vector128<Byte>>(_dataTable.inArray1Ptr); + var right = Unsafe.Read<Vector128<Byte>>(_dataTable.inArray2Ptr); + var result = Sse2.Xor(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((Byte*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((Byte*)(_dataTable.inArray2Ptr)); + var result = Sse2.Xor(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray2Ptr)); + var result = Sse2.Xor(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__XorByte(); + var result = Sse2.Xor(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse2.Xor(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128<Byte> left, Vector128<Byte> right, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[ElementCount]; + Byte[] inArray2 = new Byte[ElementCount]; + Byte[] outArray = new Byte[ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Byte, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[ElementCount]; + Byte[] inArray2 = new Byte[ElementCount]; + Byte[] outArray = new Byte[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Byte, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Byte, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Byte, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Byte[] left, Byte[] right, Byte[] result, [CallerMemberName] string method = "") + { + if ((byte)(left[0] ^ right[0]) != result[0]) + { + Succeeded = false; + } + else + { + for (var i = 1; i < left.Length; i++) + { + if ((byte)(left[i] ^ right[i]) != result[i]) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Sse2)}.{nameof(Sse2.Xor)}<Byte>: {method} failed:"); + Console.WriteLine($" left: ({string.Join(", ", left)})"); + Console.WriteLine($" right: ({string.Join(", ", right)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Xor.Double.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Xor.Double.cs new file mode 100644 index 0000000000..3bbf24a14f --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Xor.Double.cs @@ -0,0 +1,315 @@ +// 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 XorDouble() + { + var test = new SimpleBinaryOpTest__XorDouble(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + // 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(); + + // 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(); + + // 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 works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + 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__XorDouble + { + private const int VectorSize = 16; + private const int ElementCount = VectorSize / sizeof(Double); + + private static Double[] _data1 = new Double[ElementCount]; + private static Double[] _data2 = new Double[ElementCount]; + + private static Vector128<Double> _clsVar1; + private static Vector128<Double> _clsVar2; + + private Vector128<Double> _fld1; + private Vector128<Double> _fld2; + + private SimpleBinaryOpTest__DataTable<Double> _dataTable; + + static SimpleBinaryOpTest__XorDouble() + { + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (double)(random.NextDouble()); _data2[i] = (double)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Double>, byte>(ref _clsVar1), ref Unsafe.As<Double, byte>(ref _data2[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Double>, byte>(ref _clsVar2), ref Unsafe.As<Double, byte>(ref _data1[0]), VectorSize); + } + + public SimpleBinaryOpTest__XorDouble() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (double)(random.NextDouble()); _data2[i] = (double)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Double>, byte>(ref _fld1), ref Unsafe.As<Double, byte>(ref _data1[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Double>, byte>(ref _fld2), ref Unsafe.As<Double, byte>(ref _data2[0]), VectorSize); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (double)(random.NextDouble()); _data2[i] = (double)(random.NextDouble()); } + _dataTable = new SimpleBinaryOpTest__DataTable<Double>(_data1, _data2, new Double[ElementCount], VectorSize); + } + + public bool IsSupported => Sse2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse2.Xor( + Unsafe.Read<Vector128<Double>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<Double>>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse2.Xor( + Sse2.LoadVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Double*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse2.Xor( + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Xor), new Type[] { typeof(Vector128<Double>), typeof(Vector128<Double>) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector128<Double>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<Double>>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Double>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Xor), new Type[] { typeof(Vector128<Double>), typeof(Vector128<Double>) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Double*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Double>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Xor), new Type[] { typeof(Vector128<Double>), typeof(Vector128<Double>) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Double>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse2.Xor( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read<Vector128<Double>>(_dataTable.inArray1Ptr); + var right = Unsafe.Read<Vector128<Double>>(_dataTable.inArray2Ptr); + var result = Sse2.Xor(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((Double*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((Double*)(_dataTable.inArray2Ptr)); + var result = Sse2.Xor(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray2Ptr)); + var result = Sse2.Xor(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__XorDouble(); + var result = Sse2.Xor(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse2.Xor(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128<Double> left, Vector128<Double> right, void* result, [CallerMemberName] string method = "") + { + Double[] inArray1 = new Double[ElementCount]; + Double[] inArray2 = new Double[ElementCount]; + Double[] outArray = new Double[ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Double[] inArray1 = new Double[ElementCount]; + Double[] inArray2 = new Double[ElementCount]; + Double[] outArray = new Double[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Double[] left, Double[] right, Double[] result, [CallerMemberName] string method = "") + { + if ((BitConverter.DoubleToInt64Bits(left[0]) ^ BitConverter.DoubleToInt64Bits(right[0])) != BitConverter.DoubleToInt64Bits(result[0])) + { + Succeeded = false; + } + else + { + for (var i = 1; i < left.Length; i++) + { + if ((BitConverter.DoubleToInt64Bits(left[i]) ^ BitConverter.DoubleToInt64Bits(right[i])) != BitConverter.DoubleToInt64Bits(result[i])) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Sse2)}.{nameof(Sse2.Xor)}<Double>: {method} failed:"); + Console.WriteLine($" left: ({string.Join(", ", left)})"); + Console.WriteLine($" right: ({string.Join(", ", right)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Xor.Int16.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Xor.Int16.cs new file mode 100644 index 0000000000..c14ac4d434 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Xor.Int16.cs @@ -0,0 +1,315 @@ +// 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 XorInt16() + { + var test = new SimpleBinaryOpTest__XorInt16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + // 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(); + + // 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(); + + // 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 works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + 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__XorInt16 + { + private const int VectorSize = 16; + private const int ElementCount = VectorSize / sizeof(Int16); + + private static Int16[] _data1 = new Int16[ElementCount]; + private static Int16[] _data2 = new Int16[ElementCount]; + + private static Vector128<Int16> _clsVar1; + private static Vector128<Int16> _clsVar2; + + private Vector128<Int16> _fld1; + private Vector128<Int16> _fld2; + + private SimpleBinaryOpTest__DataTable<Int16> _dataTable; + + static SimpleBinaryOpTest__XorInt16() + { + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (short)(random.Next(short.MinValue, short.MaxValue)); _data2[i] = (short)(random.Next(short.MinValue, short.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int16>, byte>(ref _clsVar1), ref Unsafe.As<Int16, byte>(ref _data2[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int16>, byte>(ref _clsVar2), ref Unsafe.As<Int16, byte>(ref _data1[0]), VectorSize); + } + + public SimpleBinaryOpTest__XorInt16() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (short)(random.Next(short.MinValue, short.MaxValue)); _data2[i] = (short)(random.Next(short.MinValue, short.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int16>, byte>(ref _fld1), ref Unsafe.As<Int16, byte>(ref _data1[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int16>, byte>(ref _fld2), ref Unsafe.As<Int16, byte>(ref _data2[0]), VectorSize); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (short)(random.Next(short.MinValue, short.MaxValue)); _data2[i] = (short)(random.Next(short.MinValue, short.MaxValue)); } + _dataTable = new SimpleBinaryOpTest__DataTable<Int16>(_data1, _data2, new Int16[ElementCount], VectorSize); + } + + public bool IsSupported => Sse2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse2.Xor( + Unsafe.Read<Vector128<Int16>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<Int16>>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse2.Xor( + Sse2.LoadVector128((Int16*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Int16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse2.Xor( + Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Xor), new Type[] { typeof(Vector128<Int16>), typeof(Vector128<Int16>) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector128<Int16>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<Int16>>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Int16>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Xor), new Type[] { typeof(Vector128<Int16>), typeof(Vector128<Int16>) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Int16*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Int16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Int16>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Xor), new Type[] { typeof(Vector128<Int16>), typeof(Vector128<Int16>) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Int16>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse2.Xor( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read<Vector128<Int16>>(_dataTable.inArray1Ptr); + var right = Unsafe.Read<Vector128<Int16>>(_dataTable.inArray2Ptr); + var result = Sse2.Xor(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((Int16*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((Int16*)(_dataTable.inArray2Ptr)); + var result = Sse2.Xor(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray2Ptr)); + var result = Sse2.Xor(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__XorInt16(); + var result = Sse2.Xor(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse2.Xor(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128<Int16> left, Vector128<Int16> right, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[ElementCount]; + Int16[] inArray2 = new Int16[ElementCount]; + Int16[] outArray = new Int16[ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int16, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[ElementCount]; + Int16[] inArray2 = new Int16[ElementCount]; + Int16[] outArray = new Int16[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int16, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int16, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int16, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int16[] left, Int16[] right, Int16[] result, [CallerMemberName] string method = "") + { + if ((short)(left[0] ^ right[0]) != result[0]) + { + Succeeded = false; + } + else + { + for (var i = 1; i < left.Length; i++) + { + if ((short)(left[i] ^ right[i]) != result[i]) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Sse2)}.{nameof(Sse2.Xor)}<Int16>: {method} failed:"); + Console.WriteLine($" left: ({string.Join(", ", left)})"); + Console.WriteLine($" right: ({string.Join(", ", right)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Xor.Int32.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Xor.Int32.cs new file mode 100644 index 0000000000..2a7970763b --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Xor.Int32.cs @@ -0,0 +1,315 @@ +// 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 XorInt32() + { + var test = new SimpleBinaryOpTest__XorInt32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + // 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(); + + // 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(); + + // 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 works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + 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__XorInt32 + { + private const int VectorSize = 16; + private const int ElementCount = VectorSize / sizeof(Int32); + + private static Int32[] _data1 = new Int32[ElementCount]; + private static Int32[] _data2 = new Int32[ElementCount]; + + private static Vector128<Int32> _clsVar1; + private static Vector128<Int32> _clsVar2; + + private Vector128<Int32> _fld1; + private Vector128<Int32> _fld2; + + private SimpleBinaryOpTest__DataTable<Int32> _dataTable; + + static SimpleBinaryOpTest__XorInt32() + { + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (int)(random.Next(int.MinValue, int.MaxValue)); _data2[i] = (int)(random.Next(int.MinValue, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int32>, byte>(ref _clsVar1), ref Unsafe.As<Int32, byte>(ref _data2[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int32>, byte>(ref _clsVar2), ref Unsafe.As<Int32, byte>(ref _data1[0]), VectorSize); + } + + public SimpleBinaryOpTest__XorInt32() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (int)(random.Next(int.MinValue, int.MaxValue)); _data2[i] = (int)(random.Next(int.MinValue, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int32>, byte>(ref _fld1), ref Unsafe.As<Int32, byte>(ref _data1[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int32>, byte>(ref _fld2), ref Unsafe.As<Int32, byte>(ref _data2[0]), VectorSize); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (int)(random.Next(int.MinValue, int.MaxValue)); _data2[i] = (int)(random.Next(int.MinValue, int.MaxValue)); } + _dataTable = new SimpleBinaryOpTest__DataTable<Int32>(_data1, _data2, new Int32[ElementCount], VectorSize); + } + + public bool IsSupported => Sse2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse2.Xor( + Unsafe.Read<Vector128<Int32>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<Int32>>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse2.Xor( + Sse2.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Int32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse2.Xor( + Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Xor), new Type[] { typeof(Vector128<Int32>), typeof(Vector128<Int32>) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector128<Int32>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<Int32>>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Int32>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Xor), new Type[] { typeof(Vector128<Int32>), typeof(Vector128<Int32>) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Int32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Int32>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Xor), new Type[] { typeof(Vector128<Int32>), typeof(Vector128<Int32>) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Int32>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse2.Xor( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read<Vector128<Int32>>(_dataTable.inArray1Ptr); + var right = Unsafe.Read<Vector128<Int32>>(_dataTable.inArray2Ptr); + var result = Sse2.Xor(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((Int32*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((Int32*)(_dataTable.inArray2Ptr)); + var result = Sse2.Xor(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray2Ptr)); + var result = Sse2.Xor(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__XorInt32(); + var result = Sse2.Xor(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse2.Xor(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128<Int32> left, Vector128<Int32> right, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[ElementCount]; + Int32[] inArray2 = new Int32[ElementCount]; + Int32[] outArray = new Int32[ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int32, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[ElementCount]; + Int32[] inArray2 = new Int32[ElementCount]; + Int32[] outArray = new Int32[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int32, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int32, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int32, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int32[] left, Int32[] right, Int32[] result, [CallerMemberName] string method = "") + { + if ((int)(left[0] ^ right[0]) != result[0]) + { + Succeeded = false; + } + else + { + for (var i = 1; i < left.Length; i++) + { + if ((int)(left[i] ^ right[i]) != result[i]) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Sse2)}.{nameof(Sse2.Xor)}<Int32>: {method} failed:"); + Console.WriteLine($" left: ({string.Join(", ", left)})"); + Console.WriteLine($" right: ({string.Join(", ", right)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Xor.Int64.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Xor.Int64.cs new file mode 100644 index 0000000000..be2e77e03f --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Xor.Int64.cs @@ -0,0 +1,315 @@ +// 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 XorInt64() + { + var test = new SimpleBinaryOpTest__XorInt64(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + // 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(); + + // 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(); + + // 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 works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + 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__XorInt64 + { + private const int VectorSize = 16; + private const int ElementCount = VectorSize / sizeof(Int64); + + private static Int64[] _data1 = new Int64[ElementCount]; + private static Int64[] _data2 = new Int64[ElementCount]; + + private static Vector128<Int64> _clsVar1; + private static Vector128<Int64> _clsVar2; + + private Vector128<Int64> _fld1; + private Vector128<Int64> _fld2; + + private SimpleBinaryOpTest__DataTable<Int64> _dataTable; + + static SimpleBinaryOpTest__XorInt64() + { + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (long)(random.Next(int.MinValue, int.MaxValue)); _data2[i] = (long)(random.Next(int.MinValue, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int64>, byte>(ref _clsVar1), ref Unsafe.As<Int64, byte>(ref _data2[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int64>, byte>(ref _clsVar2), ref Unsafe.As<Int64, byte>(ref _data1[0]), VectorSize); + } + + public SimpleBinaryOpTest__XorInt64() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (long)(random.Next(int.MinValue, int.MaxValue)); _data2[i] = (long)(random.Next(int.MinValue, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int64>, byte>(ref _fld1), ref Unsafe.As<Int64, byte>(ref _data1[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int64>, byte>(ref _fld2), ref Unsafe.As<Int64, byte>(ref _data2[0]), VectorSize); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (long)(random.Next(int.MinValue, int.MaxValue)); _data2[i] = (long)(random.Next(int.MinValue, int.MaxValue)); } + _dataTable = new SimpleBinaryOpTest__DataTable<Int64>(_data1, _data2, new Int64[ElementCount], VectorSize); + } + + public bool IsSupported => Sse2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse2.Xor( + Unsafe.Read<Vector128<Int64>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<Int64>>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse2.Xor( + Sse2.LoadVector128((Int64*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Int64*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse2.Xor( + Sse2.LoadAlignedVector128((Int64*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Int64*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Xor), new Type[] { typeof(Vector128<Int64>), typeof(Vector128<Int64>) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector128<Int64>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<Int64>>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Int64>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Xor), new Type[] { typeof(Vector128<Int64>), typeof(Vector128<Int64>) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Int64*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Int64*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Int64>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Xor), new Type[] { typeof(Vector128<Int64>), typeof(Vector128<Int64>) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Int64*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Int64*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Int64>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse2.Xor( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read<Vector128<Int64>>(_dataTable.inArray1Ptr); + var right = Unsafe.Read<Vector128<Int64>>(_dataTable.inArray2Ptr); + var result = Sse2.Xor(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((Int64*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((Int64*)(_dataTable.inArray2Ptr)); + var result = Sse2.Xor(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((Int64*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((Int64*)(_dataTable.inArray2Ptr)); + var result = Sse2.Xor(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__XorInt64(); + var result = Sse2.Xor(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse2.Xor(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128<Int64> left, Vector128<Int64> right, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[ElementCount]; + Int64[] inArray2 = new Int64[ElementCount]; + Int64[] outArray = new Int64[ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int64, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[ElementCount]; + Int64[] inArray2 = new Int64[ElementCount]; + Int64[] outArray = new Int64[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int64, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int64, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int64, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int64[] left, Int64[] right, Int64[] result, [CallerMemberName] string method = "") + { + if ((long)(left[0] ^ right[0]) != result[0]) + { + Succeeded = false; + } + else + { + for (var i = 1; i < left.Length; i++) + { + if ((long)(left[i] ^ right[i]) != result[i]) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Sse2)}.{nameof(Sse2.Xor)}<Int64>: {method} failed:"); + Console.WriteLine($" left: ({string.Join(", ", left)})"); + Console.WriteLine($" right: ({string.Join(", ", right)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Xor.SByte.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Xor.SByte.cs new file mode 100644 index 0000000000..77d25337a2 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Xor.SByte.cs @@ -0,0 +1,315 @@ +// 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 XorSByte() + { + var test = new SimpleBinaryOpTest__XorSByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + // 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(); + + // 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(); + + // 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 works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + 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__XorSByte + { + private const int VectorSize = 16; + private const int ElementCount = VectorSize / sizeof(SByte); + + private static SByte[] _data1 = new SByte[ElementCount]; + private static SByte[] _data2 = new SByte[ElementCount]; + + private static Vector128<SByte> _clsVar1; + private static Vector128<SByte> _clsVar2; + + private Vector128<SByte> _fld1; + private Vector128<SByte> _fld2; + + private SimpleBinaryOpTest__DataTable<SByte> _dataTable; + + static SimpleBinaryOpTest__XorSByte() + { + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue)); _data2[i] = (sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<SByte>, byte>(ref _clsVar1), ref Unsafe.As<SByte, byte>(ref _data2[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<SByte>, byte>(ref _clsVar2), ref Unsafe.As<SByte, byte>(ref _data1[0]), VectorSize); + } + + public SimpleBinaryOpTest__XorSByte() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue)); _data2[i] = (sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<SByte>, byte>(ref _fld1), ref Unsafe.As<SByte, byte>(ref _data1[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<SByte>, byte>(ref _fld2), ref Unsafe.As<SByte, byte>(ref _data2[0]), VectorSize); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue)); _data2[i] = (sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue)); } + _dataTable = new SimpleBinaryOpTest__DataTable<SByte>(_data1, _data2, new SByte[ElementCount], VectorSize); + } + + public bool IsSupported => Sse2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse2.Xor( + Unsafe.Read<Vector128<SByte>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<SByte>>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse2.Xor( + Sse2.LoadVector128((SByte*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((SByte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse2.Xor( + Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Xor), new Type[] { typeof(Vector128<SByte>), typeof(Vector128<SByte>) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector128<SByte>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<SByte>>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<SByte>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Xor), new Type[] { typeof(Vector128<SByte>), typeof(Vector128<SByte>) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((SByte*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((SByte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<SByte>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Xor), new Type[] { typeof(Vector128<SByte>), typeof(Vector128<SByte>) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<SByte>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse2.Xor( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read<Vector128<SByte>>(_dataTable.inArray1Ptr); + var right = Unsafe.Read<Vector128<SByte>>(_dataTable.inArray2Ptr); + var result = Sse2.Xor(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((SByte*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((SByte*)(_dataTable.inArray2Ptr)); + var result = Sse2.Xor(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArray2Ptr)); + var result = Sse2.Xor(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__XorSByte(); + var result = Sse2.Xor(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse2.Xor(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128<SByte> left, Vector128<SByte> right, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[ElementCount]; + SByte[] inArray2 = new SByte[ElementCount]; + SByte[] outArray = new SByte[ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<SByte, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[ElementCount]; + SByte[] inArray2 = new SByte[ElementCount]; + SByte[] outArray = new SByte[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<SByte, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<SByte, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<SByte, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(SByte[] left, SByte[] right, SByte[] result, [CallerMemberName] string method = "") + { + if ((sbyte)(left[0] ^ right[0]) != result[0]) + { + Succeeded = false; + } + else + { + for (var i = 1; i < left.Length; i++) + { + if ((sbyte)(left[i] ^ right[i]) != result[i]) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Sse2)}.{nameof(Sse2.Xor)}<SByte>: {method} failed:"); + Console.WriteLine($" left: ({string.Join(", ", left)})"); + Console.WriteLine($" right: ({string.Join(", ", right)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Xor.UInt16.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Xor.UInt16.cs new file mode 100644 index 0000000000..89aad87dba --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Xor.UInt16.cs @@ -0,0 +1,315 @@ +// 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 XorUInt16() + { + var test = new SimpleBinaryOpTest__XorUInt16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + // 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(); + + // 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(); + + // 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 works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + 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__XorUInt16 + { + private const int VectorSize = 16; + private const int ElementCount = VectorSize / sizeof(UInt16); + + private static UInt16[] _data1 = new UInt16[ElementCount]; + private static UInt16[] _data2 = new UInt16[ElementCount]; + + private static Vector128<UInt16> _clsVar1; + private static Vector128<UInt16> _clsVar2; + + private Vector128<UInt16> _fld1; + private Vector128<UInt16> _fld2; + + private SimpleBinaryOpTest__DataTable<UInt16> _dataTable; + + static SimpleBinaryOpTest__XorUInt16() + { + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (ushort)(random.Next(0, ushort.MaxValue)); _data2[i] = (ushort)(random.Next(0, ushort.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt16>, byte>(ref _clsVar1), ref Unsafe.As<UInt16, byte>(ref _data2[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt16>, byte>(ref _clsVar2), ref Unsafe.As<UInt16, byte>(ref _data1[0]), VectorSize); + } + + public SimpleBinaryOpTest__XorUInt16() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (ushort)(random.Next(0, ushort.MaxValue)); _data2[i] = (ushort)(random.Next(0, ushort.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt16>, byte>(ref _fld1), ref Unsafe.As<UInt16, byte>(ref _data1[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt16>, byte>(ref _fld2), ref Unsafe.As<UInt16, byte>(ref _data2[0]), VectorSize); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (ushort)(random.Next(0, ushort.MaxValue)); _data2[i] = (ushort)(random.Next(0, ushort.MaxValue)); } + _dataTable = new SimpleBinaryOpTest__DataTable<UInt16>(_data1, _data2, new UInt16[ElementCount], VectorSize); + } + + public bool IsSupported => Sse2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse2.Xor( + Unsafe.Read<Vector128<UInt16>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<UInt16>>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse2.Xor( + Sse2.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse2.Xor( + Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Xor), new Type[] { typeof(Vector128<UInt16>), typeof(Vector128<UInt16>) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector128<UInt16>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<UInt16>>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<UInt16>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Xor), new Type[] { typeof(Vector128<UInt16>), typeof(Vector128<UInt16>) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<UInt16>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Xor), new Type[] { typeof(Vector128<UInt16>), typeof(Vector128<UInt16>) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<UInt16>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse2.Xor( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read<Vector128<UInt16>>(_dataTable.inArray1Ptr); + var right = Unsafe.Read<Vector128<UInt16>>(_dataTable.inArray2Ptr); + var result = Sse2.Xor(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)); + var result = Sse2.Xor(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArray2Ptr)); + var result = Sse2.Xor(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__XorUInt16(); + var result = Sse2.Xor(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse2.Xor(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128<UInt16> left, Vector128<UInt16> right, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[ElementCount]; + UInt16[] inArray2 = new UInt16[ElementCount]; + UInt16[] outArray = new UInt16[ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt16, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[ElementCount]; + UInt16[] inArray2 = new UInt16[ElementCount]; + UInt16[] outArray = new UInt16[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt16, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt16, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt16, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt16[] left, UInt16[] right, UInt16[] result, [CallerMemberName] string method = "") + { + if ((ushort)(left[0] ^ right[0]) != result[0]) + { + Succeeded = false; + } + else + { + for (var i = 1; i < left.Length; i++) + { + if ((ushort)(left[i] ^ right[i]) != result[i]) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Sse2)}.{nameof(Sse2.Xor)}<UInt16>: {method} failed:"); + Console.WriteLine($" left: ({string.Join(", ", left)})"); + Console.WriteLine($" right: ({string.Join(", ", right)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Xor.UInt32.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Xor.UInt32.cs new file mode 100644 index 0000000000..479b11151d --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Xor.UInt32.cs @@ -0,0 +1,315 @@ +// 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 XorUInt32() + { + var test = new SimpleBinaryOpTest__XorUInt32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + // 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(); + + // 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(); + + // 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 works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + 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__XorUInt32 + { + private const int VectorSize = 16; + private const int ElementCount = VectorSize / sizeof(UInt32); + + private static UInt32[] _data1 = new UInt32[ElementCount]; + private static UInt32[] _data2 = new UInt32[ElementCount]; + + private static Vector128<UInt32> _clsVar1; + private static Vector128<UInt32> _clsVar2; + + private Vector128<UInt32> _fld1; + private Vector128<UInt32> _fld2; + + private SimpleBinaryOpTest__DataTable<UInt32> _dataTable; + + static SimpleBinaryOpTest__XorUInt32() + { + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (uint)(random.Next(0, int.MaxValue)); _data2[i] = (uint)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt32>, byte>(ref _clsVar1), ref Unsafe.As<UInt32, byte>(ref _data2[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt32>, byte>(ref _clsVar2), ref Unsafe.As<UInt32, byte>(ref _data1[0]), VectorSize); + } + + public SimpleBinaryOpTest__XorUInt32() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (uint)(random.Next(0, int.MaxValue)); _data2[i] = (uint)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt32>, byte>(ref _fld1), ref Unsafe.As<UInt32, byte>(ref _data1[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt32>, byte>(ref _fld2), ref Unsafe.As<UInt32, byte>(ref _data2[0]), VectorSize); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (uint)(random.Next(0, int.MaxValue)); _data2[i] = (uint)(random.Next(0, int.MaxValue)); } + _dataTable = new SimpleBinaryOpTest__DataTable<UInt32>(_data1, _data2, new UInt32[ElementCount], VectorSize); + } + + public bool IsSupported => Sse2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse2.Xor( + Unsafe.Read<Vector128<UInt32>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<UInt32>>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse2.Xor( + Sse2.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse2.Xor( + Sse2.LoadAlignedVector128((UInt32*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((UInt32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Xor), new Type[] { typeof(Vector128<UInt32>), typeof(Vector128<UInt32>) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector128<UInt32>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<UInt32>>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<UInt32>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Xor), new Type[] { typeof(Vector128<UInt32>), typeof(Vector128<UInt32>) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<UInt32>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Xor), new Type[] { typeof(Vector128<UInt32>), typeof(Vector128<UInt32>) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((UInt32*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((UInt32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<UInt32>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse2.Xor( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read<Vector128<UInt32>>(_dataTable.inArray1Ptr); + var right = Unsafe.Read<Vector128<UInt32>>(_dataTable.inArray2Ptr); + var result = Sse2.Xor(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)); + var result = Sse2.Xor(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((UInt32*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((UInt32*)(_dataTable.inArray2Ptr)); + var result = Sse2.Xor(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__XorUInt32(); + var result = Sse2.Xor(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse2.Xor(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128<UInt32> left, Vector128<UInt32> right, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[ElementCount]; + UInt32[] inArray2 = new UInt32[ElementCount]; + UInt32[] outArray = new UInt32[ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt32, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[ElementCount]; + UInt32[] inArray2 = new UInt32[ElementCount]; + UInt32[] outArray = new UInt32[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt32, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt32, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt32, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt32[] left, UInt32[] right, UInt32[] result, [CallerMemberName] string method = "") + { + if ((uint)(left[0] ^ right[0]) != result[0]) + { + Succeeded = false; + } + else + { + for (var i = 1; i < left.Length; i++) + { + if ((uint)(left[i] ^ right[i]) != result[i]) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Sse2)}.{nameof(Sse2.Xor)}<UInt32>: {method} failed:"); + Console.WriteLine($" left: ({string.Join(", ", left)})"); + Console.WriteLine($" right: ({string.Join(", ", right)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Xor.UInt64.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Xor.UInt64.cs new file mode 100644 index 0000000000..2a448a4c48 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Xor.UInt64.cs @@ -0,0 +1,315 @@ +// 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 XorUInt64() + { + var test = new SimpleBinaryOpTest__XorUInt64(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + // 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(); + + // 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(); + + // 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 works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + 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__XorUInt64 + { + private const int VectorSize = 16; + private const int ElementCount = VectorSize / sizeof(UInt64); + + private static UInt64[] _data1 = new UInt64[ElementCount]; + private static UInt64[] _data2 = new UInt64[ElementCount]; + + private static Vector128<UInt64> _clsVar1; + private static Vector128<UInt64> _clsVar2; + + private Vector128<UInt64> _fld1; + private Vector128<UInt64> _fld2; + + private SimpleBinaryOpTest__DataTable<UInt64> _dataTable; + + static SimpleBinaryOpTest__XorUInt64() + { + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (ulong)(random.Next(0, int.MaxValue)); _data2[i] = (ulong)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt64>, byte>(ref _clsVar1), ref Unsafe.As<UInt64, byte>(ref _data2[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt64>, byte>(ref _clsVar2), ref Unsafe.As<UInt64, byte>(ref _data1[0]), VectorSize); + } + + public SimpleBinaryOpTest__XorUInt64() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (ulong)(random.Next(0, int.MaxValue)); _data2[i] = (ulong)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt64>, byte>(ref _fld1), ref Unsafe.As<UInt64, byte>(ref _data1[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt64>, byte>(ref _fld2), ref Unsafe.As<UInt64, byte>(ref _data2[0]), VectorSize); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (ulong)(random.Next(0, int.MaxValue)); _data2[i] = (ulong)(random.Next(0, int.MaxValue)); } + _dataTable = new SimpleBinaryOpTest__DataTable<UInt64>(_data1, _data2, new UInt64[ElementCount], VectorSize); + } + + public bool IsSupported => Sse2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Sse2.Xor( + Unsafe.Read<Vector128<UInt64>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<UInt64>>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse2.Xor( + Sse2.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((UInt64*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse2.Xor( + Sse2.LoadAlignedVector128((UInt64*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((UInt64*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Xor), new Type[] { typeof(Vector128<UInt64>), typeof(Vector128<UInt64>) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector128<UInt64>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector128<UInt64>>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<UInt64>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Xor), new Type[] { typeof(Vector128<UInt64>), typeof(Vector128<UInt64>) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((UInt64*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<UInt64>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse2).GetMethod(nameof(Sse2.Xor), new Type[] { typeof(Vector128<UInt64>), typeof(Vector128<UInt64>) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((UInt64*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((UInt64*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<UInt64>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Sse2.Xor( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read<Vector128<UInt64>>(_dataTable.inArray1Ptr); + var right = Unsafe.Read<Vector128<UInt64>>(_dataTable.inArray2Ptr); + var result = Sse2.Xor(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse2.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((UInt64*)(_dataTable.inArray2Ptr)); + var result = Sse2.Xor(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse2.LoadAlignedVector128((UInt64*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((UInt64*)(_dataTable.inArray2Ptr)); + var result = Sse2.Xor(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__XorUInt64(); + var result = Sse2.Xor(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Sse2.Xor(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128<UInt64> left, Vector128<UInt64> right, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray1 = new UInt64[ElementCount]; + UInt64[] inArray2 = new UInt64[ElementCount]; + UInt64[] outArray = new UInt64[ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt64, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray1 = new UInt64[ElementCount]; + UInt64[] inArray2 = new UInt64[ElementCount]; + UInt64[] outArray = new UInt64[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt64, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt64, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt64, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt64[] left, UInt64[] right, UInt64[] result, [CallerMemberName] string method = "") + { + if ((ulong)(left[0] ^ right[0]) != result[0]) + { + Succeeded = false; + } + else + { + for (var i = 1; i < left.Length; i++) + { + if ((ulong)(left[i] ^ right[i]) != result[i]) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Sse2)}.{nameof(Sse2.Xor)}<UInt64>: {method} failed:"); + Console.WriteLine($" left: ({string.Join(", ", left)})"); + Console.WriteLine($" right: ({string.Join(", ", right)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Xor.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Xor.cs deleted file mode 100644 index d2788b500a..0000000000 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Xor.cs +++ /dev/null @@ -1,187 +0,0 @@ -// 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. -// - -using System; -using System.Runtime.Intrinsics; -using System.Runtime.Intrinsics.X86; - -namespace IntelHardwareIntrinsicTest -{ - internal static partial class Program - { - const int Pass = 100; - const int Fail = 0; - - static unsafe int Main(string[] args) - { - int testResult = Pass; - int testsCount = 21; - string methodUnderTestName = nameof(Sse2.Xor); - - if (Sse2.IsSupported) - { - using (var doubleTable = TestTableSse2<double>.Create(testsCount)) - using (var longTable = TestTableSse2<long>.Create(testsCount)) - using (var ulongTable = TestTableSse2<ulong>.Create(testsCount)) - using (var intTable = TestTableSse2<int>.Create(testsCount)) - using (var uintTable = TestTableSse2<uint>.Create(testsCount)) - using (var shortTable = TestTableSse2<short>.Create(testsCount)) - using (var ushortTable = TestTableSse2<ushort>.Create(testsCount)) - using (var sbyteTable = TestTableSse2<sbyte>.Create(testsCount)) - using (var byteTable = TestTableSse2<byte>.Create(testsCount)) - { - for (int i = 0; i < testsCount; i++) - { - (Vector128<double>, Vector128<double>, Vector128<double>) value = doubleTable[i]; - var result = Sse2.Xor(value.Item1, value.Item2); - doubleTable.SetOutArray(result); - } - - for (int i = 0; i < testsCount; i++) - { - (Vector128<long>, Vector128<long>, Vector128<long>) value = longTable[i]; - var result = Sse2.Xor(value.Item1, value.Item2); - longTable.SetOutArray(result); - } - - for (int i = 0; i < testsCount; i++) - { - (Vector128<ulong>, Vector128<ulong>, Vector128<ulong>) value = ulongTable[i]; - var result = Sse2.Xor(value.Item1, value.Item2); - ulongTable.SetOutArray(result); - } - - for (int i = 0; i < testsCount; i++) - { - (Vector128<int>, Vector128<int>, Vector128<int>) value = intTable[i]; - var result = Sse2.Xor(value.Item1, value.Item2); - intTable.SetOutArray(result); - } - - for (int i = 0; i < testsCount; i++) - { - (Vector128<uint>, Vector128<uint>, Vector128<uint>) value = uintTable[i]; - var result = Sse2.Xor(value.Item1, value.Item2); - uintTable.SetOutArray(result); - } - - for (int i = 0; i < testsCount; i++) - { - (Vector128<short>, Vector128<short>, Vector128<short>) value = shortTable[i]; - var result = Sse2.Xor(value.Item1, value.Item2); - shortTable.SetOutArray(result); - } - - for (int i = 0; i < testsCount; i++) - { - (Vector128<ushort>, Vector128<ushort>, Vector128<ushort>) value = ushortTable[i]; - var result = Sse2.Xor(value.Item1, value.Item2); - ushortTable.SetOutArray(result); - } - - for (int i = 0; i < testsCount; i++) - { - (Vector128<sbyte>, Vector128<sbyte>, Vector128<sbyte>) value = sbyteTable[i]; - var result = Sse2.Xor(value.Item1, value.Item2); - sbyteTable.SetOutArray(result); - } - - for (int i = 0; i < testsCount; i++) - { - (Vector128<byte>, Vector128<byte>, Vector128<byte>) value = byteTable[i]; - var result = Sse2.Xor(value.Item1, value.Item2); - byteTable.SetOutArray(result); - } - - CheckMethod<double> checkDouble = (double x, double y, double z, ref double a) => (a = BitwiseXor(x, y)) == z; - - if (!doubleTable.CheckResult(checkDouble)) - { - PrintError(doubleTable, methodUnderTestName, "(double x, double y, double z, ref double a) => (a = BitwiseXor(x, y)) == z", checkDouble); - testResult = Fail; - } - - CheckMethod<long> checkLong = (long x, long y, long z, ref long a) => (a = x ^ y) == z; - - if (!longTable.CheckResult(checkLong)) - { - PrintError(longTable, methodUnderTestName, "(long x, long y, long z, ref long a) => (a = x ^ y) == z", checkLong); - testResult = Fail; - } - - CheckMethod<ulong> checkUlong = (ulong x, ulong y, ulong z, ref ulong a) => (a = x ^ y) == z; - - if (!longTable.CheckResult(checkLong)) - { - PrintError(ulongTable, methodUnderTestName, "(ulong x, ulong y, ulong z, ref ulong a) => (a = x ^ y) == z", checkUlong); - testResult = Fail; - } - - CheckMethod<int> checkInt32 = (int x, int y, int z, ref int a) => (a = x ^ y) == z; - - if (!intTable.CheckResult(checkInt32)) - { - PrintError(intTable, methodUnderTestName, "(int x, int y, int z, ref int a) => (a = x ^ y) == z", checkInt32); - testResult = Fail; - } - - CheckMethod<uint> checkUInt32 = (uint x, uint y, uint z, ref uint a) => (a = x ^ y) == z; - - if (!uintTable.CheckResult(checkUInt32)) - { - PrintError(uintTable, methodUnderTestName, "(uint x, uint y, uint z, ref uint a) => (a = x ^ y) == z", checkUInt32); - testResult = Fail; - } - - CheckMethod<short> checkInt16 = (short x, short y, short z, ref short a) => (a = (short)(x ^ y)) == z; - - if (!shortTable.CheckResult(checkInt16)) - { - PrintError(shortTable, methodUnderTestName, "(short x, short y, short z, ref short a) => (a = (short)(x ^ y)) == z", checkInt16); - testResult = Fail; - } - - CheckMethod<ushort> checkUInt16 = (ushort x, ushort y, ushort z, ref ushort a) => (a = (ushort)(x ^ y)) == z; - - if (!ushortTable.CheckResult(checkUInt16)) - { - PrintError(ushortTable, methodUnderTestName, "(ushort x, ushort y, ushort z, ref ushort a) => (a = (ushort)(x ^ y)) == z", checkUInt16); - testResult = Fail; - } - - CheckMethod<sbyte> checkSByte = (sbyte x, sbyte y, sbyte z, ref sbyte a) => (a = (sbyte)(x ^ y)) == z; - - if (!sbyteTable.CheckResult(checkSByte)) - { - PrintError(sbyteTable, methodUnderTestName, "(sbyte x, sbyte y, sbyte z, ref sbyte a) => (a = (sbyte)(x ^ y)) == z", checkSByte); - testResult = Fail; - } - - CheckMethod<byte> checkByte = (byte x, byte y, byte z, ref byte a) => (a = (byte)(x ^ y)) == z; - - if (!byteTable.CheckResult(checkByte)) - { - PrintError(byteTable, methodUnderTestName, "(byte x, byte y, byte z, ref byte a) => (a = (byte)(x ^ y)) == z", checkByte); - testResult = Fail; - } - } - } - else - { - Console.WriteLine($"Sse2.IsSupported: {Sse2.IsSupported}, skipped tests of {typeof(Sse2)}.{methodUnderTestName}"); - } - - return testResult; - } - - public static unsafe double BitwiseXor(double x, double y) - { - var xUlong = BitConverter.ToUInt64(BitConverter.GetBytes(x)); - var yUlong = BitConverter.ToUInt64(BitConverter.GetBytes(y)); - var longAnd = xUlong ^ yUlong; - return BitConverter.ToDouble(BitConverter.GetBytes(longAnd)); - } - } -} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Xor_r.csproj b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Xor_r.csproj deleted file mode 100644 index e354b97ae0..0000000000 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Xor_r.csproj +++ /dev/null @@ -1,38 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" /> - <PropertyGroup> - <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> - <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> - <SchemaVersion>2.0</SchemaVersion> - <ProjectGuid>{C2DA0767-1509-4FFE-BC4C-F58FC761413C}</ProjectGuid> - <OutputType>Exe</OutputType> - <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> - <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir> - <AllowUnsafeBlocks>true</AllowUnsafeBlocks> - </PropertyGroup> - <!-- Default configurations to help VS understand the configurations --> - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> - </PropertyGroup> - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' " /> - <ItemGroup> - <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies"> - <Visible>False</Visible> - </CodeAnalysisDependentAssemblyPaths> - </ItemGroup> - <PropertyGroup> - <DebugType>None</DebugType> - <Optimize> - </Optimize> - </PropertyGroup> - <ItemGroup> - <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" /> - </ItemGroup> - <ItemGroup> - <Compile Include="Xor.cs" /> - <Compile Include="TestTableSse2.cs" /> - </ItemGroup> - <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" /> - <PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' "> - </PropertyGroup> -</Project>
\ No newline at end of file diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Xor_ro.csproj b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Xor_ro.csproj deleted file mode 100644 index 8af5c632ea..0000000000 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Xor_ro.csproj +++ /dev/null @@ -1,37 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" /> - <PropertyGroup> - <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> - <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> - <SchemaVersion>2.0</SchemaVersion> - <ProjectGuid>{D926F753-0262-4EE2-BFA2-F0FDA0F51899}</ProjectGuid> - <OutputType>Exe</OutputType> - <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> - <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir> - <AllowUnsafeBlocks>true</AllowUnsafeBlocks> - </PropertyGroup> - <!-- Default configurations to help VS understand the configurations --> - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> - </PropertyGroup> - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' " /> - <ItemGroup> - <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies"> - <Visible>False</Visible> - </CodeAnalysisDependentAssemblyPaths> - </ItemGroup> - <PropertyGroup> - <DebugType>None</DebugType> - <Optimize>True</Optimize> - </PropertyGroup> - <ItemGroup> - <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" /> - </ItemGroup> - <ItemGroup> - <Compile Include="Xor.cs" /> - <Compile Include="TestTableSse2.cs" /> - </ItemGroup> - <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" /> - <PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' "> - </PropertyGroup> -</Project>
\ No newline at end of file |