diff --git a/src/tests/Common/CoreCLRTestLibrary/Generator.cs b/src/tests/Common/CoreCLRTestLibrary/Generator.cs index 76ebbc05c1ce17..074ffe0250b452 100644 --- a/src/tests/Common/CoreCLRTestLibrary/Generator.cs +++ b/src/tests/Common/CoreCLRTestLibrary/Generator.cs @@ -47,6 +47,11 @@ public static int? Seed } } + public static bool GetBool() + { + return m_rand.Next(0, 2) == 1; + } + // returns a byte array of random data public static void GetBytes(int new_seed, byte[] buffer) { diff --git a/src/tests/Common/CoreCLRTestLibrary/Vectors.cs b/src/tests/Common/CoreCLRTestLibrary/Vectors.cs index cf4c14934c6152..44b37cb1bdde55 100644 --- a/src/tests/Common/CoreCLRTestLibrary/Vectors.cs +++ b/src/tests/Common/CoreCLRTestLibrary/Vectors.cs @@ -24,6 +24,25 @@ public static Vector GetRandomVector() { data[i] = TestLibrary.Generator.GetByte(); } + + // TODO-ARM64-SVE: Some test functions do not support propagation of NaN/Inf values. + if (typeof(T) == typeof(float)) + { + for (int i = 0; i < vsize / sizeof(float); i++) + { + // Clear bit 23 to suppress generation of NaN/Inf values. + data[i * sizeof(float) + 2] &= byte.CreateTruncating(~(1 << 7)); + } + } + else if (typeof(T) == typeof(double)) + { + for (int i = 0; i < vsize / sizeof(double); i++) + { + // Clear bit 52 to suppress generation of NaN/Inf values. + data[i * sizeof(double) + 6] &= byte.CreateTruncating(~(1 << 4)); + } + } + return new Vector(data.AsSpan()); } @@ -37,7 +56,15 @@ public static Vector GetRandomMask() long count = vsize / tsize; for (int i = 0; i < count; i++) { - data[i * tsize] |= (byte)(TestLibrary.Generator.GetByte() & 1); + // Bias the generator to produces zero values at least 50% of the time. + // Elements that pass through this choice will be filled with random data. + if (TestLibrary.Generator.GetBool()) + { + for (int j = 0; j < tsize; j++) + { + data[i * tsize + j] = TestLibrary.Generator.GetByte(); + } + } } return new Vector(data.AsSpan()); diff --git a/src/tests/JIT/HardwareIntrinsics/Arm/Shared/Helpers.cs b/src/tests/JIT/HardwareIntrinsics/Arm/Shared/Helpers.cs index ab0388d112bb92..035c1b48be22c6 100644 --- a/src/tests/JIT/HardwareIntrinsics/Arm/Shared/Helpers.cs +++ b/src/tests/JIT/HardwareIntrinsics/Arm/Shared/Helpers.cs @@ -29,12 +29,21 @@ public static Vector InitVector(Func f) return new Vector(arr); } + public static T[] ConvertVectorToMask(T[] vector) where T : IBinaryInteger + { + T[] result = new T[vector.Length]; + for (int i = 0; i < vector.Length; i++) + { + result[i] = vector[i] == T.Zero ? T.Zero : T.One; + } + return result; + } + public static T[] CreateMaskForFirstActiveElement(T[] mask, T[] srcMask) where T : unmanaged, IBinaryInteger { int count = srcMask.Length; - T[] result = new T[count]; - Array.Copy(srcMask, result, count); + T[] result = ConvertVectorToMask(srcMask); for (int i = 0; i < count; i++) { @@ -1580,19 +1589,51 @@ public static ulong FusedAddHalving(ulong op1, ulong op2) public static long FusedAddHalving(long op1, long op2) { long sum = op1 + op2; - bool carry = sum < op1; - return (sum >> 1) + (carry ? 1L << 63 : 0); + + if (op1 > 0 && op2 > 0 && sum < 0) + { + // Addition overflows into the sign bit, which simulates an + // unsigned 64-bit addition. We need to perform a logical shift + // to make sure the sign-bit is clear on the half value. + return (long)((ulong)sum >>> 1); + } + else if (op1 < 0 && op2 < 0 && sum > 0) + { + // Addition of negative values overflows beyond the sign-bit into + // the positive range. The halved value will be OK but we need to + // reinstate the sign bit which was lost. + return (long)((ulong)(sum >> 1) | (1UL << 63)); + } + else + { + // No overflow, simply halve preserving sign-bit. + return sum >> 1; + } } public static long FusedSubtractHalving(long op1, long op2) { - ulong uop1 = (ulong)op1; - ulong uop2 = (ulong)op2; + long diff = op1 - op2; - ulong udiff = uop1 - uop2; - long sdiff = unchecked((long)udiff); - - return sdiff >> 1; + if (op1 > 0 && op2 < 0 && diff < 0) + { + // Subtract of negative value overflows into the sign bit We need + // to perform a logical shift to make sure the sign-bit is clear + // on the half value. + return (long)((ulong)diff >>> 1); + } + else if (op1 < 0 && op2 > 0 && diff > 0) + { + // Subtraction of positive value overflows beyond the sign-bit into + // the positive range. The halved value will be OK but we need to + // reinstate the sign bit which was lost. + return (long)((ulong)(diff >> 1) | (1UL << 63)); + } + else + { + // No overflow, simply halve preserving sign-bit. + return diff >> 1; + } } public static ulong FusedSubtractHalving(ulong op1, ulong op2) @@ -1602,7 +1643,6 @@ public static ulong FusedSubtractHalving(ulong op1, ulong op2) return (diff >> 1) + (overflow ? 1UL << 63 : 0); } - public static uint FusedAddRoundedHalving(uint op1, uint op2) => (uint)((ulong)((ulong)op1 + (ulong)op2 + 1) >> 1); public static uint FusedSubtractHalving(uint op1, uint op2) => (uint)((ulong)((ulong)op1 - (ulong)op2) >> 1); @@ -2942,7 +2982,7 @@ private static sbyte SignedShift(sbyte op1, sbyte op2, bool rounding = false, bo { if (shiftOvf) { - result = op2 < 0 ? sbyte.MinValue : sbyte.MaxValue; + return op1 > 0 ? sbyte.MaxValue : sbyte.MinValue; } } } @@ -3140,8 +3180,19 @@ private static (byte val, bool ovf) SubtractOvf(byte op1, byte op2) public static sbyte AddSaturate(sbyte op1, sbyte op2) { - var (result, ovf) = AddOvf(op1, op2); - return ovf ? (result > 0 ? sbyte.MinValue : sbyte.MaxValue) : result; + int result = op1 + op2; + if (result > sbyte.MaxValue) + { + return sbyte.MaxValue; + } + else if (result < sbyte.MinValue) + { + return sbyte.MinValue; + } + else + { + return (sbyte)result; + } } public static sbyte AddSaturate(sbyte op1, byte op2) @@ -7517,7 +7568,7 @@ public static T[] CreateBreakPropagateMask(T[] op1, T[] op2) where T : IBinar if (LastActive(mask, op1) != T.Zero) { - Array.Copy(op2, result, count); + result = ConvertVectorToMask(op2); } return result; @@ -8185,7 +8236,34 @@ public static N SubtractRoundedHighNarrowingOdd(N even, W op1, W op2, int return Odd(even, SubtractRoundedHighNarrowing(op1, op2), i); } - public static long FusedAddRoundedHalving(long op1, long op2) => (long)((ulong)(op1 + op2 + 1) >> 1); + public static long FusedAddRoundedHalving(long op1, long op2) + { + bool overflow = false; + long sum = 0; + try + { + sum = checked(op1 + op2 + 1); + } + catch (OverflowException) + { + overflow = true; + sum = op1 + op2 + 1; + } + + // See FusedAddHalving for description of cases. + if (op1 > 0 && op2 > 0 && overflow) + { + return (long)((ulong)sum >>> 1); + } + else if (op1 < 0 && op2 < 0 && overflow) + { + return (long)((ulong)(sum >> 1) | (1UL << 63)); + } + else + { + return sum >> 1; + } + } public static ulong FusedAddRoundedHalving(ulong op1, ulong op2) { diff --git a/src/tests/JIT/HardwareIntrinsics/Arm/Shared/_SveBinaryOpTestTemplate.template b/src/tests/JIT/HardwareIntrinsics/Arm/Shared/_SveBinaryOpTestTemplate.template index c579f5bbef2cc1..010b829a775fc8 100644 --- a/src/tests/JIT/HardwareIntrinsics/Arm/Shared/_SveBinaryOpTestTemplate.template +++ b/src/tests/JIT/HardwareIntrinsics/Arm/Shared/_SveBinaryOpTestTemplate.template @@ -85,117 +85,49 @@ namespace JIT.HardwareIntrinsics.Arm public sealed unsafe class {TemplateName}BinaryOpTest__{TestName} { - private struct DataTable - { - private byte[] inArray1; - private byte[] inArray2; - private byte[] outArray; - - private GCHandle inHandle1; - private GCHandle inHandle2; - private GCHandle outHandle; - - private ulong alignment; - - public DataTable({Op1BaseType}[] inArray1, {Op2BaseType}[] inArray2, {RetBaseType}[] outArray, int alignment) - { - int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf<{Op1BaseType}>(); - int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf<{Op2BaseType}>(); - int sizeOfoutArray = outArray.Length * Unsafe.SizeOf<{RetBaseType}>(); - if ((alignment != 64 && alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) - { - throw new ArgumentException($"Invalid value of alignment: {alignment}, sizeOfinArray1: {sizeOfinArray1}, sizeOfinArray2: {sizeOfinArray2}, sizeOfoutArray: {sizeOfoutArray}"); - } - - this.inArray1 = new byte[alignment * 2]; - this.inArray2 = new byte[alignment * 2]; - this.outArray = new byte[alignment * 2]; - - this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); - this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); - this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); - - this.alignment = (ulong)alignment; - - Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As<{Op1BaseType}, byte>(ref inArray1[0]), (uint)sizeOfinArray1); - Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As<{Op2BaseType}, byte>(ref inArray2[0]), (uint)sizeOfinArray2); - } - - public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); - public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); - public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); - - public void Dispose() - { - inHandle1.Free(); - inHandle2.Free(); - outHandle.Free(); - } - - private static unsafe void* Align(byte* buffer, ulong expectedAlignment) - { - return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); - } - } - private struct TestStruct { - public {Op1VectorType}<{Op1BaseType}> _fld1; - public {Op2VectorType}<{Op2BaseType}> _fld2; + public Vector<{Op1BaseType}> _fld1; + public Vector<{Op2BaseType}> _fld2; - public static TestStruct Create() + public static TestStruct Create(Vector<{Op1BaseType}> op1, Vector<{Op2BaseType}> op2) { var testStruct = new TestStruct(); - - for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = {NextValueOp1}; } - Unsafe.CopyBlockUnaligned(ref Unsafe.As<{Op1VectorType}<{Op1BaseType}>, byte>(ref testStruct._fld1), ref Unsafe.As<{Op1BaseType}, byte>(ref _data1[0]), (uint)Unsafe.SizeOf<{Op1VectorType}<{Op1BaseType}>>()); - for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = {NextValueOp2}; } - Unsafe.CopyBlockUnaligned(ref Unsafe.As<{Op2VectorType}<{Op2BaseType}>, byte>(ref testStruct._fld2), ref Unsafe.As<{Op2BaseType}, byte>(ref _data2[0]), (uint)Unsafe.SizeOf<{Op2VectorType}<{Op2BaseType}>>()); - + testStruct._fld1 = op1; + testStruct._fld2 = op2; return testStruct; } public void RunStructFldScenario({TemplateName}BinaryOpTest__{TestName} testClass) { var result = {Isa}.{Method}(_fld1, _fld2); - - Unsafe.Write(testClass._dataTable.outArrayPtr, result); - testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + testClass.ValidateResult(_fld1, _fld2, result); } } private static readonly int LargestVectorSize = {LargestVectorSize}; - private static readonly int Op1ElementCount = Unsafe.SizeOf<{Op1VectorType}<{Op1BaseType}>>() / sizeof({Op1BaseType}); - private static readonly int Op2ElementCount = Unsafe.SizeOf<{Op2VectorType}<{Op2BaseType}>>() / sizeof({Op2BaseType}); - private static readonly int RetElementCount = Unsafe.SizeOf<{RetVectorType}<{RetBaseType}>>() / sizeof({RetBaseType}); + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof({Op1BaseType}); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof({Op2BaseType}); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof({RetBaseType}); - private static {RetBaseType}[] _maskData = new {RetBaseType}[RetElementCount]; - private static {Op1BaseType}[] _data1 = new {Op1BaseType}[Op1ElementCount]; - private static {Op2BaseType}[] _data2 = new {Op2BaseType}[Op2ElementCount]; - - private {RetVectorType}<{RetBaseType}> _mask; - private {Op1VectorType}<{Op1BaseType}> _fld1; - private {Op2VectorType}<{Op2BaseType}> _fld2; - private {Op2VectorType}<{Op2BaseType}> _falseFld; - - private DataTable _dataTable; + private Vector<{RetBaseType}> _mask; + private Vector<{Op1BaseType}> _fld1; + private Vector<{Op2BaseType}> _fld2; + private Vector<{Op2BaseType}> _falseFld; + private TestLibrary.Vectors.PinnedVector<{Op1BaseType}> _pinnedOp1; + private TestLibrary.Vectors.PinnedVector<{Op2BaseType}> _pinnedOp2; public {TemplateName}BinaryOpTest__{TestName}() { Succeeded = true; - for (var i = 0; i < RetElementCount; i++) { _maskData[i] = ({RetBaseType})({NextValueOp1} % 2); } - Unsafe.CopyBlockUnaligned(ref Unsafe.As<{RetVectorType}<{RetBaseType}>, byte>(ref _mask), ref Unsafe.As<{RetBaseType}, byte>(ref _maskData[0]), (uint)Unsafe.SizeOf<{RetVectorType}<{RetBaseType}>>()); - for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = {NextValueOp1}; } - Unsafe.CopyBlockUnaligned(ref Unsafe.As<{Op1VectorType}<{Op1BaseType}>, byte>(ref _fld1), ref Unsafe.As<{Op1BaseType}, byte>(ref _data1[0]), (uint)Unsafe.SizeOf<{Op1VectorType}<{Op1BaseType}>>()); - for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = {NextValueOp2}; } - Unsafe.CopyBlockUnaligned(ref Unsafe.As<{Op2VectorType}<{Op2BaseType}>, byte>(ref _fld2), ref Unsafe.As<{Op2BaseType}, byte>(ref _data2[0]), (uint)Unsafe.SizeOf<{Op2VectorType}<{Op2BaseType}>>()); - Unsafe.CopyBlockUnaligned(ref Unsafe.As<{Op2VectorType}<{Op2BaseType}>, byte>(ref _falseFld), ref Unsafe.As<{Op2BaseType}, byte>(ref _data2[0]), (uint)Unsafe.SizeOf<{Op2VectorType}<{Op2BaseType}>>()); - - for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = {NextValueOp1}; } - for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = {NextValueOp2}; } - _dataTable = new DataTable(_data1, _data2, new {RetBaseType}[RetElementCount], LargestVectorSize); + _mask = TestLibrary.Vectors.GetRandomMask<{RetBaseType}>(); + _fld1 = TestLibrary.Vectors.GetRandomVector<{Op1BaseType}>(); + _fld2 = TestLibrary.Vectors.GetRandomVector<{Op2BaseType}>(); + _falseFld = _fld2; + _pinnedOp1 = new TestLibrary.Vectors.PinnedVector<{Op1BaseType}>(_fld1, LargestVectorSize); + _pinnedOp2 = new TestLibrary.Vectors.PinnedVector<{Op2BaseType}>(_fld2, LargestVectorSize); } public bool IsSupported => {Isa}.IsSupported; @@ -206,67 +138,56 @@ namespace JIT.HardwareIntrinsics.Arm { TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); - var result = {Isa}.{Method}( - Unsafe.Read<{Op1VectorType}<{Op1BaseType}>>(_dataTable.inArray1Ptr), - Unsafe.Read<{Op2VectorType}<{Op2BaseType}>>(_dataTable.inArray2Ptr) - ); + var result = {Isa}.{Method}(_pinnedOp1.Value, _pinnedOp2.Value); - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + ValidateResult(_pinnedOp1.Value, _pinnedOp2.Value, result); } public void RunBasicScenario_Load() { TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); - {Op1VectorType}<{Op1BaseType}> loadMask = Sve.CreateTrueMask{Op1BaseType}(SveMaskPattern.All); + Vector<{Op1BaseType}> loadMask = Sve.CreateTrueMask{Op1BaseType}(SveMaskPattern.All); var result = {Isa}.{Method}( - {LoadIsa}.Load{Op1VectorType}(loadMask, ({Op1BaseType}*)(_dataTable.inArray1Ptr)), - {LoadIsa}.Load{Op2VectorType}(loadMask, ({Op2BaseType}*)(_dataTable.inArray2Ptr)) + {LoadIsa}.LoadVector(loadMask, ({Op1BaseType}*)(_pinnedOp1.Ptr)), + {LoadIsa}.LoadVector(loadMask, ({Op2BaseType}*)(_pinnedOp2.Ptr)) ); - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + ValidateResult(_pinnedOp1.Value, _pinnedOp2.Value, result); } public void RunReflectionScenario_UnsafeRead() { TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); - var result = typeof({Isa}).GetMethod(nameof({Isa}.{Method}), new Type[] { typeof({Op1VectorType}<{Op1BaseType}>), typeof({Op2VectorType}<{Op2BaseType}>) }) - .Invoke(null, new object[] { - Unsafe.Read<{Op1VectorType}<{Op1BaseType}>>(_dataTable.inArray1Ptr), - Unsafe.Read<{Op2VectorType}<{Op2BaseType}>>(_dataTable.inArray2Ptr) - }); + var result = typeof({Isa}).GetMethod(nameof({Isa}.{Method}), new Type[] { typeof(Vector<{Op1BaseType}>), typeof(Vector<{Op2BaseType}>) }) + .Invoke(null, new object[] { _pinnedOp1.Value, _pinnedOp2.Value }); - Unsafe.Write(_dataTable.outArrayPtr, ({RetVectorType}<{RetBaseType}>)(result)); - ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + ValidateResult(_pinnedOp1.Value, _pinnedOp2.Value, (Vector<{RetBaseType}>)(result)); } public void RunLclVarScenario_UnsafeRead() { TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); - var op1 = Unsafe.Read<{Op1VectorType}<{Op1BaseType}>>(_dataTable.inArray1Ptr); - var op2 = Unsafe.Read<{Op2VectorType}<{Op2BaseType}>>(_dataTable.inArray2Ptr); + var op1 = _pinnedOp1.Value; + var op2 = _pinnedOp2.Value; var result = {Isa}.{Method}(op1, op2); - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(op1, op2, _dataTable.outArrayPtr); + ValidateResult(op1, op2, result); } public void RunSameLclVarScenario_UnsafeRead() { TestLibrary.TestFramework.BeginScenario(nameof(RunSameLclVarScenario_UnsafeRead)); - var op = Unsafe.Read<{Op1VectorType}<{Op1BaseType}>>(_dataTable.inArray1Ptr); + var op = _pinnedOp1.Value; var op1 = op; var op2 = op; var result = {Isa}.{Method}(op1, op2); - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(op1, op2, _dataTable.outArrayPtr); + ValidateResult(op1, op2, result); } public void RunClassFldScenario() @@ -275,8 +196,7 @@ namespace JIT.HardwareIntrinsics.Arm var result = {Isa}.{Method}(_fld1, _fld2); - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + ValidateResult(_fld1, _fld2, result); } public void RunSameClassFldScenario() @@ -285,26 +205,24 @@ namespace JIT.HardwareIntrinsics.Arm var result = {Isa}.{Method}(_fld1, _fld1); - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_fld1, _fld1, _dataTable.outArrayPtr); + ValidateResult(_fld1, _fld1, result); } public void RunStructLclFldScenario() { TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); - var test = TestStruct.Create(); + var test = TestStruct.Create(_fld1, _fld2); var result = {Isa}.{Method}(test._fld1, test._fld2); - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + ValidateResult(test._fld1, test._fld2, result); } public void RunStructFldScenario() { TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); - var test = TestStruct.Create(); + var test = TestStruct.Create(_fld1, _fld2); test.RunStructFldScenario(this); } @@ -314,19 +232,19 @@ namespace JIT.HardwareIntrinsics.Arm ConditionalSelectScenario_TrueValue(_mask, _fld1, _fld2, _fld1); TestLibrary.TestFramework.BeginScenario("ConditionalSelect_Op1_zero - operation in TrueValue"); - ConditionalSelectScenario_TrueValue({RetVectorType}<{RetBaseType}>.Zero, _fld1, _fld2, _fld1); + ConditionalSelectScenario_TrueValue(Vector<{RetBaseType}>.Zero, _fld1, _fld2, _fld1); TestLibrary.TestFramework.BeginScenario("ConditionalSelect_Op1_all - operation in TrueValue"); - ConditionalSelectScenario_TrueValue({RetVectorType}<{RetBaseType}>.AllBitsSet, _fld1, _fld2, _fld1); + ConditionalSelectScenario_TrueValue(Vector<{RetBaseType}>.AllBitsSet, _fld1, _fld2, _fld1); TestLibrary.TestFramework.BeginScenario("ConditionalSelect_Op1_mask - operation in FalseValue"); ConditionalSelectScenario_FalseValue(_mask, _fld1, _fld2, _fld1); TestLibrary.TestFramework.BeginScenario("ConditionalSelect_Op1_zero - operation in FalseValue"); - ConditionalSelectScenario_FalseValue({RetVectorType}<{RetBaseType}>.Zero, _fld1, _fld2, _fld1); + ConditionalSelectScenario_FalseValue(Vector<{RetBaseType}>.Zero, _fld1, _fld2, _fld1); TestLibrary.TestFramework.BeginScenario("ConditionalSelect_Op1_all - operation in FalseValue"); - ConditionalSelectScenario_FalseValue({RetVectorType}<{RetBaseType}>.AllBitsSet, _fld1, _fld2, _fld1); + ConditionalSelectScenario_FalseValue(Vector<{RetBaseType}>.AllBitsSet, _fld1, _fld2, _fld1); } public void ConditionalSelect_Op2() @@ -335,19 +253,19 @@ namespace JIT.HardwareIntrinsics.Arm ConditionalSelectScenario_TrueValue(_mask, _fld1, _fld2, _fld2); TestLibrary.TestFramework.BeginScenario("ConditionalSelect_Op2_zero - operation in TrueValue"); - ConditionalSelectScenario_TrueValue({RetVectorType}<{RetBaseType}>.Zero, _fld1, _fld2, _fld2); + ConditionalSelectScenario_TrueValue(Vector<{RetBaseType}>.Zero, _fld1, _fld2, _fld2); TestLibrary.TestFramework.BeginScenario("ConditionalSelect_Op2_all - operation in TrueValue"); - ConditionalSelectScenario_TrueValue({RetVectorType}<{RetBaseType}>.AllBitsSet, _fld1, _fld2, _fld2); + ConditionalSelectScenario_TrueValue(Vector<{RetBaseType}>.AllBitsSet, _fld1, _fld2, _fld2); TestLibrary.TestFramework.BeginScenario("ConditionalSelect_Op2_mask - operation in FalseValue"); ConditionalSelectScenario_FalseValue(_mask, _fld1, _fld2, _fld2); TestLibrary.TestFramework.BeginScenario("ConditionalSelect_Op2_zero - operation in FalseValue"); - ConditionalSelectScenario_FalseValue({RetVectorType}<{RetBaseType}>.Zero, _fld1, _fld2, _fld2); + ConditionalSelectScenario_FalseValue(Vector<{RetBaseType}>.Zero, _fld1, _fld2, _fld2); TestLibrary.TestFramework.BeginScenario("ConditionalSelect_Op2_all - operation in FalseValue"); - ConditionalSelectScenario_FalseValue({RetVectorType}<{RetBaseType}>.AllBitsSet, _fld1, _fld2, _fld2); + ConditionalSelectScenario_FalseValue(Vector<{RetBaseType}>.AllBitsSet, _fld1, _fld2, _fld2); } public void ConditionalSelect_FalseOp() @@ -356,58 +274,54 @@ namespace JIT.HardwareIntrinsics.Arm ConditionalSelectScenario_TrueValue(_mask, _fld1, _fld2, _falseFld); TestLibrary.TestFramework.BeginScenario("ConditionalSelect_FalseOp_zero - operation in TrueValue"); - ConditionalSelectScenario_TrueValue({RetVectorType}<{RetBaseType}>.Zero, _fld1, _fld2, _falseFld); + ConditionalSelectScenario_TrueValue(Vector<{RetBaseType}>.Zero, _fld1, _fld2, _falseFld); TestLibrary.TestFramework.BeginScenario("ConditionalSelect_FalseOp_all - operation in TrueValue"); - ConditionalSelectScenario_TrueValue({RetVectorType}<{RetBaseType}>.AllBitsSet, _fld1, _fld2, _falseFld); + ConditionalSelectScenario_TrueValue(Vector<{RetBaseType}>.AllBitsSet, _fld1, _fld2, _falseFld); TestLibrary.TestFramework.BeginScenario("ConditionalSelect_FalseOp_mask - operation in FalseValue"); ConditionalSelectScenario_FalseValue(_mask, _fld1, _fld2, _falseFld); TestLibrary.TestFramework.BeginScenario("ConditionalSelect_FalseOp_zero - operation in FalseValue"); - ConditionalSelectScenario_FalseValue({RetVectorType}<{RetBaseType}>.Zero, _fld1, _fld2, _falseFld); + ConditionalSelectScenario_FalseValue(Vector<{RetBaseType}>.Zero, _fld1, _fld2, _falseFld); TestLibrary.TestFramework.BeginScenario("ConditionalSelect_FalseOp_all - operation in FalseValue"); - ConditionalSelectScenario_FalseValue({RetVectorType}<{RetBaseType}>.AllBitsSet, _fld1, _fld2, _falseFld); + ConditionalSelectScenario_FalseValue(Vector<{RetBaseType}>.AllBitsSet, _fld1, _fld2, _falseFld); } public void ConditionalSelect_ZeroOp() { TestLibrary.TestFramework.BeginScenario("ConditionalSelect_ZeroOp_mask - operation in TrueValue"); - ConditionalSelectScenario_TrueValue(_mask, _fld1, _fld2, {RetVectorType}<{RetBaseType}>.Zero); + ConditionalSelectScenario_TrueValue(_mask, _fld1, _fld2, Vector<{RetBaseType}>.Zero); TestLibrary.TestFramework.BeginScenario("ConditionalSelect_ZeroOp_zero - operation in TrueValue"); - ConditionalSelectScenario_TrueValue({RetVectorType}<{RetBaseType}>.Zero, _fld1, _fld2, {RetVectorType}<{RetBaseType}>.Zero); + ConditionalSelectScenario_TrueValue(Vector<{RetBaseType}>.Zero, _fld1, _fld2, Vector<{RetBaseType}>.Zero); TestLibrary.TestFramework.BeginScenario("ConditionalSelect_ZeroOp_all - operation in TrueValue"); - ConditionalSelectScenario_TrueValue({RetVectorType}<{RetBaseType}>.AllBitsSet, _fld1, _fld2, {RetVectorType}<{RetBaseType}>.Zero); + ConditionalSelectScenario_TrueValue(Vector<{RetBaseType}>.AllBitsSet, _fld1, _fld2, Vector<{RetBaseType}>.Zero); TestLibrary.TestFramework.BeginScenario("ConditionalSelect_ZeroOp_mask - operation in FalseValue"); - ConditionalSelectScenario_FalseValue(_mask, _fld1, _fld2, {RetVectorType}<{RetBaseType}>.Zero); + ConditionalSelectScenario_FalseValue(_mask, _fld1, _fld2, Vector<{RetBaseType}>.Zero); TestLibrary.TestFramework.BeginScenario("ConditionalSelect_ZeroOp_zero - operation in FalseValue"); - ConditionalSelectScenario_FalseValue({RetVectorType}<{RetBaseType}>.Zero, _fld1, _fld2, {RetVectorType}<{RetBaseType}>.Zero); + ConditionalSelectScenario_FalseValue(Vector<{RetBaseType}>.Zero, _fld1, _fld2, Vector<{RetBaseType}>.Zero); TestLibrary.TestFramework.BeginScenario("ConditionalSelect_ZeroOp_all - operation in FalseValue"); - ConditionalSelectScenario_FalseValue({RetVectorType}<{RetBaseType}>.AllBitsSet, _fld1, _fld2, {RetVectorType}<{RetBaseType}>.Zero); + ConditionalSelectScenario_FalseValue(Vector<{RetBaseType}>.AllBitsSet, _fld1, _fld2, Vector<{RetBaseType}>.Zero); } [method: MethodImpl(MethodImplOptions.AggressiveInlining)] - private void ConditionalSelectScenario_TrueValue({RetVectorType}<{RetBaseType}> mask, {Op1VectorType}<{Op1BaseType}> op1, {Op2VectorType}<{Op2BaseType}> op2, {RetVectorType}<{RetBaseType}> falseOp) + private void ConditionalSelectScenario_TrueValue(Vector<{RetBaseType}> mask, Vector<{Op1BaseType}> op1, Vector<{Op2BaseType}> op2, Vector<{RetBaseType}> falseOp) { var result = Sve.ConditionalSelect(mask, {Isa}.{Method}(op1, op2), falseOp); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateConditionalSelectResult_TrueValue(mask, op1, op2, falseOp, _dataTable.outArrayPtr); + ValidateConditionalSelectResult(mask, op1, op2, falseOp, result); } [method: MethodImpl(MethodImplOptions.AggressiveInlining)] - private void ConditionalSelectScenario_FalseValue({RetVectorType}<{RetBaseType}> mask, {Op1VectorType}<{Op1BaseType}> op1, {Op2VectorType}<{Op2BaseType}> op2, {RetVectorType}<{RetBaseType}> trueOp) + private void ConditionalSelectScenario_FalseValue(Vector<{RetBaseType}> mask, Vector<{Op1BaseType}> op1, Vector<{Op2BaseType}> op2, Vector<{RetBaseType}> trueOp) { var result = Sve.ConditionalSelect(mask, trueOp, {Isa}.{Method}(op1, op2)); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateConditionalSelectResult_FalseValue(mask, op1, op2, trueOp, _dataTable.outArrayPtr); + ValidateConditionalSelectResult(mask, op1, op2, trueOp, result, false); } public void RunUnsupportedScenario() @@ -431,7 +345,14 @@ namespace JIT.HardwareIntrinsics.Arm } } - private void ValidateConditionalSelectResult_TrueValue({RetVectorType}<{RetBaseType}> maskOp, {Op1VectorType}<{Op1BaseType}> leftOp, {Op2VectorType}<{Op2BaseType}> rightOp, {RetVectorType}<{RetBaseType}> falseOp, void* output, [CallerMemberName] string method = "") + private void ValidateConditionalSelectResult( + Vector<{RetBaseType}> maskOp, + Vector<{Op1BaseType}> leftOp, + Vector<{Op2BaseType}> rightOp, + Vector<{RetBaseType}> falseOp, + Vector<{RetBaseType}> output, + bool trueMode = true, + [CallerMemberName] string method = "") { {RetBaseType}[] mask = new {RetBaseType}[RetElementCount]; {Op1BaseType}[] left = new {Op1BaseType}[Op1ElementCount]; @@ -439,15 +360,23 @@ namespace JIT.HardwareIntrinsics.Arm {RetBaseType}[] falseVal = new {RetBaseType}[RetElementCount]; {RetBaseType}[] result = new {RetBaseType}[RetElementCount]; - Unsafe.WriteUnaligned(ref Unsafe.As<{RetBaseType}, byte>(ref mask[0]), maskOp); - Unsafe.WriteUnaligned(ref Unsafe.As<{Op1BaseType}, byte>(ref left[0]), leftOp); - Unsafe.WriteUnaligned(ref Unsafe.As<{Op2BaseType}, byte>(ref right[0]), rightOp); - Unsafe.WriteUnaligned(ref Unsafe.As<{RetBaseType}, byte>(ref falseVal[0]), falseOp); - Unsafe.CopyBlockUnaligned(ref Unsafe.As<{RetBaseType}, byte>(ref result[0]), ref Unsafe.AsRef(output), (uint)Unsafe.SizeOf<{RetVectorType}<{RetBaseType}>>()); + TestLibrary.Vectors.VectorToArray(ref mask, maskOp); + TestLibrary.Vectors.VectorToArray(ref left, leftOp); + TestLibrary.Vectors.VectorToArray(ref right, rightOp); + TestLibrary.Vectors.VectorToArray(ref falseVal, falseOp); + TestLibrary.Vectors.VectorToArray(ref result, output); bool succeeded = true; - {TemplateValidationLogicForCndSel} + if (trueMode) + { + {TemplateValidationLogicForCndSel} + } + else + { + {RetBaseType}[] trueVal = falseVal; + {TemplateValidationLogicForCndSel_FalseValue} + } if (!succeeded) { @@ -463,66 +392,16 @@ namespace JIT.HardwareIntrinsics.Arm } } - private void ValidateConditionalSelectResult_FalseValue({RetVectorType}<{RetBaseType}> maskOp, {Op1VectorType}<{Op1BaseType}> leftOp, {Op2VectorType}<{Op2BaseType}> rightOp, {RetVectorType}<{RetBaseType}> trueOp, void* output, [CallerMemberName] string method = "") + private void ValidateResult(Vector<{Op1BaseType}> op1, Vector<{Op2BaseType}> op2, Vector<{RetBaseType}> output, [CallerMemberName] string method = "") { - {RetBaseType}[] mask = new {RetBaseType}[RetElementCount]; {Op1BaseType}[] left = new {Op1BaseType}[Op1ElementCount]; - {Op1BaseType}[] right = new {Op1BaseType}[Op1ElementCount]; - {RetBaseType}[] trueVal = new {RetBaseType}[RetElementCount]; + {Op2BaseType}[] right = new {Op2BaseType}[Op2ElementCount]; {RetBaseType}[] result = new {RetBaseType}[RetElementCount]; - Unsafe.WriteUnaligned(ref Unsafe.As<{RetBaseType}, byte>(ref mask[0]), maskOp); - Unsafe.WriteUnaligned(ref Unsafe.As<{Op1BaseType}, byte>(ref left[0]), leftOp); - Unsafe.WriteUnaligned(ref Unsafe.As<{Op2BaseType}, byte>(ref right[0]), rightOp); - Unsafe.WriteUnaligned(ref Unsafe.As<{RetBaseType}, byte>(ref trueVal[0]), trueOp); - Unsafe.CopyBlockUnaligned(ref Unsafe.As<{RetBaseType}, byte>(ref result[0]), ref Unsafe.AsRef(output), (uint)Unsafe.SizeOf<{RetVectorType}<{RetBaseType}>>()); - - bool succeeded = true; - - {TemplateValidationLogicForCndSel_FalseValue} - - if (!succeeded) - { - TestLibrary.TestFramework.LogInformation($"{nameof({Isa})}.{nameof({Isa}.{Method})}<{RetBaseType}>({Op1VectorType}<{Op1BaseType}>, {Op2VectorType}<{Op2BaseType}>): {method} failed:"); - TestLibrary.TestFramework.LogInformation($" mask: ({string.Join(", ", mask)})"); - TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); - TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); - TestLibrary.TestFramework.LogInformation($" trueOp: ({string.Join(", ", trueVal)})"); - TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); - TestLibrary.TestFramework.LogInformation(string.Empty); + TestLibrary.Vectors.VectorToArray(ref left, op1); + TestLibrary.Vectors.VectorToArray(ref right, op2); + TestLibrary.Vectors.VectorToArray(ref result, output); - Succeeded = false; - } - } - - private void ValidateResult({Op1VectorType}<{Op1BaseType}> op1, {Op2VectorType}<{Op2BaseType}> op2, void* result, [CallerMemberName] string method = "") - { - {Op1BaseType}[] inArray1 = new {Op1BaseType}[Op1ElementCount]; - {Op2BaseType}[] inArray2 = new {Op2BaseType}[Op2ElementCount]; - {RetBaseType}[] outArray = new {RetBaseType}[RetElementCount]; - - Unsafe.WriteUnaligned(ref Unsafe.As<{Op1BaseType}, byte>(ref inArray1[0]), op1); - Unsafe.WriteUnaligned(ref Unsafe.As<{Op2BaseType}, byte>(ref inArray2[0]), op2); - Unsafe.CopyBlockUnaligned(ref Unsafe.As<{RetBaseType}, byte>(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf<{RetVectorType}<{RetBaseType}>>()); - - ValidateResult(inArray1, inArray2, outArray, method); - } - - private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") - { - {Op1BaseType}[] inArray1 = new {Op1BaseType}[Op1ElementCount]; - {Op2BaseType}[] inArray2 = new {Op2BaseType}[Op2ElementCount]; - {RetBaseType}[] outArray = new {RetBaseType}[RetElementCount]; - - Unsafe.CopyBlockUnaligned(ref Unsafe.As<{Op1BaseType}, byte>(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf<{Op1VectorType}<{Op1BaseType}>>()); - Unsafe.CopyBlockUnaligned(ref Unsafe.As<{Op2BaseType}, byte>(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf<{Op2VectorType}<{Op2BaseType}>>()); - Unsafe.CopyBlockUnaligned(ref Unsafe.As<{RetBaseType}, byte>(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf<{RetVectorType}<{RetBaseType}>>()); - - ValidateResult(inArray1, inArray2, outArray, method); - } - - private void ValidateResult({Op1BaseType}[] left, {Op2BaseType}[] right, {RetBaseType}[] result, [CallerMemberName] string method = "") - { bool succeeded = true; {TemplateValidationLogic}