From 4738a9c5b8d10c456c6d53c88afe7cc6e0321c25 Mon Sep 17 00:00:00 2001 From: Slawomir Cygan Date: Fri, 28 Feb 2020 15:36:58 +0100 Subject: [PATCH] Allow not flusing denorms in operands This fixes tests for denorm value flush to zero in Ceil(), Log(), Log2(), Sqrt(), Sqrt2() operations. The test was assuming, that operands of denormal value are flushed before the operation, however the specification does not require that: "If the entry point is declared with the DenormFlushToZero execution mode then for the affected instuctions the denormalized result must be flushed to zero and the denormalized operands **may** be flushed to zero." VK-GL-CTS Issue: 2242 Affects: dEQP-VK.spirv_assembly.instruction.compute.float_controls.*.input_args.*_denorm_flush_to_zero Components: Vulkan Change-Id: Iedeb0d18fde3749a83be3262dba5efabf365aea2 (cherry picked from commit 0f323f593e9989190f0b8a5768aa25b594d7c1be) --- .../vktSpvAsmFloatControlsTests.cpp | 140 ++++++++++++++++-- 1 file changed, 127 insertions(+), 13 deletions(-) diff --git a/external/vulkancts/modules/vulkan/spirv_assembly/vktSpvAsmFloatControlsTests.cpp b/external/vulkancts/modules/vulkan/spirv_assembly/vktSpvAsmFloatControlsTests.cpp index 9e47c5d04..b89e0e697 100644 --- a/external/vulkancts/modules/vulkan/spirv_assembly/vktSpvAsmFloatControlsTests.cpp +++ b/external/vulkancts/modules/vulkan/spirv_assembly/vktSpvAsmFloatControlsTests.cpp @@ -121,12 +121,17 @@ enum ValueId V_MINUS_ONE_OR_CLOSE, // value used only fur fp16 subtraction result of preserved denorm and one V_PI_DIV_2, V_ZERO_OR_MINUS_ZERO, // both +0 and -0 are accepted + V_ZERO_OR_ONE, // both +0 and 1 are accepted V_ZERO_OR_FP16_DENORM_TO_FP32, // both 0 and fp32 representation of fp16 denorm are accepted V_ZERO_OR_FP16_DENORM_TO_FP64, V_ZERO_OR_FP32_DENORM_TO_FP64, V_DENORM_TIMES_TWO, V_DEGREES_DENORM, V_TRIG_ONE, // 1.0 trigonometric operations, including precision margin + V_MINUS_INF_OR_LOG_DENORM, + V_MINUS_INF_OR_LOG2_DENORM, + V_ZERO_OR_SQRT_DENORM, + V_INF_OR_INV_SQRT_DENORM, //results of conversion operations V_CONV_TO_FP16_RTZ_RESULT, @@ -974,7 +979,7 @@ TypeTestResults::TypeTestResults() { O_TRUNC, V_ZERO }, { O_ABS, V_ZERO }, { O_FLOOR, V_ZERO }, - { O_CEIL, V_ZERO }, + { O_CEIL, V_ZERO_OR_ONE }, { O_FRACT, V_ZERO }, { O_RADIANS, V_ZERO }, { O_DEGREES, V_ZERO }, @@ -991,11 +996,11 @@ TypeTestResults::TypeTestResults() { O_ACOSH, V_UNUSED }, { O_ATANH, V_ZERO }, { O_EXP, V_ONE }, - { O_LOG, V_MINUS_INF }, + { O_LOG, V_MINUS_INF_OR_LOG_DENORM }, { O_EXP2, V_ONE }, - { O_LOG2, V_MINUS_INF }, - { O_SQRT, V_ZERO }, - { O_INV_SQRT, V_INF }, + { O_LOG2, V_MINUS_INF_OR_LOG2_DENORM }, + { O_SQRT, V_ZERO_OR_SQRT_DENORM }, + { O_INV_SQRT, V_INF_OR_INV_SQRT_DENORM }, { O_MAT_DET, V_ZERO }, { O_MAT_INV, V_ZERO_OR_MINUS_ZERO }, { O_MODF, V_ZERO }, @@ -1102,7 +1107,7 @@ TypeTestResults::TypeTestResults() { O_TRUNC, V_ZERO }, { O_ABS, V_ZERO }, { O_FLOOR, V_ZERO }, - { O_CEIL, V_ZERO }, + { O_CEIL, V_ZERO_OR_ONE }, { O_FRACT, V_ZERO }, { O_RADIANS, V_ZERO }, { O_DEGREES, V_ZERO }, @@ -1119,11 +1124,11 @@ TypeTestResults::TypeTestResults() { O_ACOSH, V_UNUSED }, { O_ATANH, V_ZERO }, { O_EXP, V_ONE }, - { O_LOG, V_MINUS_INF }, + { O_LOG, V_MINUS_INF_OR_LOG_DENORM }, { O_EXP2, V_ONE }, - { O_LOG2, V_MINUS_INF }, - { O_SQRT, V_ZERO }, - { O_INV_SQRT, V_INF }, + { O_LOG2, V_MINUS_INF_OR_LOG2_DENORM }, + { O_SQRT, V_ZERO_OR_SQRT_DENORM }, + { O_INV_SQRT, V_INF_OR_INV_SQRT_DENORM }, { O_MAT_DET, V_ZERO }, { O_MAT_INV, V_ZERO_OR_MINUS_ZERO }, { O_MODF, V_ZERO }, @@ -1230,10 +1235,10 @@ TypeTestResults::TypeTestResults() { O_TRUNC, V_ZERO }, { O_ABS, V_ZERO }, { O_FLOOR, V_ZERO }, - { O_CEIL, V_ZERO }, + { O_CEIL, V_ZERO_OR_ONE }, { O_FRACT, V_ZERO }, - { O_SQRT, V_ZERO }, - { O_INV_SQRT, V_INF }, + { O_SQRT, V_ZERO_OR_SQRT_DENORM }, + { O_INV_SQRT, V_INF_OR_INV_SQRT_DENORM }, { O_MAT_DET, V_ZERO }, { O_MAT_INV, V_ZERO_OR_MINUS_ZERO }, { O_MODF, V_ZERO }, @@ -2213,6 +2218,99 @@ bool isCosResultCorrect(const TYPE& returnedFloat, TestLog& log) return false; } +template +double getFloatTypeAsDouble(FLOAT_TYPE param) +{ + return param; +} +template<> double getFloatTypeAsDouble(deFloat16 param) +{ + return deFloat16To64(param); +} + + +double getPrecisionAt(double value, float ulp, int mantissaBits) +{ + if (mantissaBits == 23) + { + FloatFormat fp32Format(-126, 127, 23, true, tcu::MAYBE, tcu::YES, tcu::MAYBE); + return fp32Format.ulp(value, ulp); + } + else if (mantissaBits == 52) + { + FloatFormat fp32Format(-1022, 1023, 52, true, tcu::MAYBE, tcu::YES, tcu::MAYBE); + return fp32Format.ulp(value, ulp); + } + else + { + DE_ASSERT(mantissaBits == 10); + FloatFormat fp16Format(-14, 15, 10, true, tcu::MAYBE); + return fp16Format.ulp(value, ulp); + } +} + +template +bool isLogResultCorrect(const TYPE& returnedFloat, FLOAT_TYPE param, REF_FUNCTION refFunction, TestLog& log) +{ + if (returnedFloat.isInf() && returnedFloat.signBit()) + return true; + + const double expected = refFunction(getFloatTypeAsDouble(param)); + const double precision = getPrecisionAt(expected, 3.0, returnedFloat.MANTISSA_BITS); + + if (deAbs(returnedFloat.asDouble() - expected) < precision) + return true; + + log << TestLog::Message << "Expected result to be -INF or in range" + << " (" << expected - precision << ", " << expected + precision << "), got " + << returnedFloat.asDouble() << TestLog::EndMessage; + return false; +} + +template +bool isInverseSqrtResultCorrect(const TYPE& returnedFloat, FLOAT_TYPE param, TestLog& log) +{ + if (returnedFloat.isInf() && !returnedFloat.signBit()) + return true; + + const double expected = 1.0/ deSqrt(getFloatTypeAsDouble(param)); + const double precision = getPrecisionAt(expected, 2.0, returnedFloat.MANTISSA_BITS); + + if (deAbs(returnedFloat.asDouble() - expected) < precision) + return true; + + log << TestLog::Message << "Expected result to be INF or in range" + << " (" << expected - precision << ", " << expected + precision << "), got " + << returnedFloat.asDouble() << TestLog::EndMessage; + return false; +} + +template +bool isSqrtResultCorrect(const TYPE& returnedFloat, FLOAT_TYPE param, TestLog& log) +{ + if (returnedFloat.isZero() && !returnedFloat.signBit()) + return true; + + + const double expected = deSqrt(getFloatTypeAsDouble(param)); + const double expectedInverseSqrt = 1.0 / expected; + const double inverseSqrtPrecision = getPrecisionAt(expectedInverseSqrt, 2.0, returnedFloat.MANTISSA_BITS); + + double expectedMin = deMin(1.0 / (expectedInverseSqrt - inverseSqrtPrecision), 1.0 / (expectedInverseSqrt + inverseSqrtPrecision)); + double expectedMax = deMax(1.0 / (expectedInverseSqrt - inverseSqrtPrecision), 1.0 / (expectedInverseSqrt + inverseSqrtPrecision)); + + expectedMin -= getPrecisionAt(expectedMin, 2.5, returnedFloat.MANTISSA_BITS); + expectedMax += getPrecisionAt(expectedMax, 2.5, returnedFloat.MANTISSA_BITS); + + if (returnedFloat.asDouble() >= expectedMin && returnedFloat.asDouble() <= expectedMax) + return true; + + log << TestLog::Message << "Expected result to be +0 or in range" + << " (" << expectedMin << ", " << expectedMax << "), got " + << returnedFloat.asDouble() << TestLog::EndMessage; + return false; +} + // Function used to compare test result with expected output. // TYPE can be Float16, Float32 or Float64. // FLOAT_TYPE can be deFloat16, float, double. @@ -2271,6 +2369,8 @@ bool compareBytes(vector& expectedBytes, AllocationSp outputAlloc, Test log << TestLog::Message << "Expected 0 or -0" << TestLog::EndMessage; return false; } + if (expectedValueId == V_ZERO_OR_ONE) + return isZeroOrOtherValue(returnedFloat, V_ONE, log); if ((expectedValueId == V_ZERO_OR_FP16_DENORM_TO_FP32) || (expectedValueId == V_ZERO_OR_FP16_DENORM_TO_FP64)) return isZeroOrOtherValue(returnedFloat, V_CONV_DENORM_SMALLER, log); if (expectedValueId == V_ZERO_OR_FP32_DENORM_TO_FP64) @@ -2292,6 +2392,20 @@ bool compareBytes(vector& expectedBytes, AllocationSp outputAlloc, Test return isAcosResultCorrect(returnedFloat, log); TypeValues typeValues; + + if (expectedValueId == V_MINUS_INF_OR_LOG_DENORM) + return isLogResultCorrect(returnedFloat, typeValues.getValue(V_DENORM), deLog, log); + + if (expectedValueId == V_MINUS_INF_OR_LOG2_DENORM) + return isLogResultCorrect(returnedFloat, typeValues.getValue(V_DENORM), deLog2, log); + + if (expectedValueId == V_ZERO_OR_SQRT_DENORM) + return isSqrtResultCorrect(returnedFloat, typeValues.getValue(V_DENORM), log); + + if (expectedValueId == V_INF_OR_INV_SQRT_DENORM) + return isInverseSqrtResultCorrect(returnedFloat, typeValues.getValue(V_DENORM), log); + + typename RawConvert::Value value; value.fp = typeValues.getValue(expectedValueId); -- 2.34.1