diff options
4 files changed, 187 insertions, 93 deletions
diff --git a/external/vulkancts/modules/vulkan/spirv_assembly/vktSpvAsm16bitStorageTests.cpp b/external/vulkancts/modules/vulkan/spirv_assembly/vktSpvAsm16bitStorageTests.cpp index cebb0d50c..4cdff5607 100644 --- a/external/vulkancts/modules/vulkan/spirv_assembly/vktSpvAsm16bitStorageTests.cpp +++ b/external/vulkancts/modules/vulkan/spirv_assembly/vktSpvAsm16bitStorageTests.cpp @@ -3603,7 +3603,9 @@ void addGraphics16BitStorageInputOutputFloat32To16Group (tcu::TestCaseGroup* tes vector<string> extensions; map<string, string> fragments = passthruFragments(); const deUint32 numDataPoints = 64; - vector<float> float32Data = getFloat32s(rnd, numDataPoints); + // Special values like inf/nan/denormal may not be preserved when float control features are not provided, + // thus values generating special float16 values must be excluded in input data here. + vector<float> float32Data = getFloat32s(rnd, numDataPoints, DE_FALSE); extensions.push_back("VK_KHR_16bit_storage"); @@ -3879,7 +3881,9 @@ void addGraphics16BitStorageInputOutputFloat16To16Group (tcu::TestCaseGroup* tes vector<string> extensions; map<string, string> fragments = passthruFragments(); const deUint32 numDataPoints = 64; - vector<deFloat16> float16Data (getFloat16s(rnd, numDataPoints)); + // Special values like inf/nan/denormal may not be preserved when float control features are not provided, + // thus those values must be excluded in the input data here. + vector<deFloat16> float16Data (getFloat16s(rnd, numDataPoints, DE_FALSE)); VulkanFeatures requiredFeatures; requiredFeatures.ext16BitStorage.storageInputOutput16 = true; @@ -7952,7 +7956,9 @@ void addGraphics16BitStorageInputOutputFloat64To16Group (tcu::TestCaseGroup* tes vector<string> extensions; map<string, string> fragments = passthruFragments(); const deUint32 numDataPoints = 64; - vector<double> float64Data = getFloat64s(rnd, numDataPoints); + // Special values like inf/nan/denormal may not be preserved when float control features are not provided, + // thus values generating special float16 values must be excluded in input data here. + vector<double> float64Data = getFloat64s(rnd, numDataPoints, DE_FALSE); extensions.push_back("VK_KHR_16bit_storage"); diff --git a/external/vulkancts/modules/vulkan/spirv_assembly/vktSpvAsmUtils.cpp b/external/vulkancts/modules/vulkan/spirv_assembly/vktSpvAsmUtils.cpp index c80786d8b..997ccad7e 100644 --- a/external/vulkancts/modules/vulkan/spirv_assembly/vktSpvAsmUtils.cpp +++ b/external/vulkancts/modules/vulkan/spirv_assembly/vktSpvAsmUtils.cpp @@ -468,19 +468,19 @@ std::vector<deInt8> getInt8s (de::Random& rnd, const deUint32 count) // Generate and return 64-bit floats // -// The first 24 number pairs are manually picked, while the rest are randomly generated. -// Expected count to be at least 24 (numPicks). -std::vector<double> getFloat64s (de::Random& rnd, deUint32 count) +// If includeSpecialFloat16Values is false, random float64 that can be converted to float16 inf/nan/denormal must be excluded +// since inf may be clamped, and nan/denormal be flushed without float control features. +// And expected count to be at least 14 (numPicks). +// Otherwise, the first 24 number pairs are manually picked, while the rest are randomly generated. +// And expected count to be at least 24 (numPicks). +std::vector<double> getFloat64s (de::Random& rnd, deUint32 count, deBool includeSpecialFloat16Values) { std::vector<double> float64; float64.reserve(count); - if (count >= 24) + if (includeSpecialFloat16Values) { - // Zero - float64.push_back(0.f); - float64.push_back(-0.f); // Infinity float64.push_back(std::numeric_limits<double>::infinity()); float64.push_back(-std::numeric_limits<double>::infinity()); @@ -490,44 +490,52 @@ std::vector<double> getFloat64s (de::Random& rnd, deUint32 count) // QNaN float64.push_back(std::numeric_limits<double>::quiet_NaN()); float64.push_back(-std::numeric_limits<double>::quiet_NaN()); - - // Denormalized 64-bit float matching 0 in 16-bit - float64.push_back(ldexp((double)1.f, -1023)); - float64.push_back(-ldexp((double)1.f, -1023)); - - // Normalized 64-bit float matching 0 in 16-bit - float64.push_back(ldexp((double)1.f, -100)); - float64.push_back(-ldexp((double)1.f, -100)); // Normalized 64-bit float with exact denormalized match in 16-bit float64.push_back(bitwiseCast<double>(deUint64(0x3B0357C299A88EA8))); float64.push_back(bitwiseCast<double>(deUint64(0xBB0357C299A88EA8))); - - // Normalized 64-bit float with exact normalized match in 16-bit - float64.push_back(ldexp((double)1.f, -14)); // 2e-14: minimum 16-bit positive normalized - float64.push_back(-ldexp((double)1.f, -14)); // 2e-14: maximum 16-bit negative normalized - // Normalized 64-bit float falling above half way within two 16-bit normalized - float64.push_back(bitwiseCast<double>(deUint64(0x3FD2000000000000))); - float64.push_back(bitwiseCast<double>(deUint64(0xBFD2000000000000))); - // Normalized 64-bit float falling exact half way within two 16-bit normalized - float64.push_back(bitwiseCast<double>(deUint64(0x3F100C0000000000))); - float64.push_back(bitwiseCast<double>(deUint64(0xBF100C0000000000))); - // Some number - float64.push_back((double)0.28125f); - float64.push_back((double)-0.28125f); // Normalized 64-bit float matching infinity in 16-bit float64.push_back(ldexp((double)1.f, 100)); float64.push_back(-ldexp((double)1.f, 100)); } + // Zero + float64.push_back(0.f); + float64.push_back(-0.f); + // Denormalized 64-bit float matching 0 in 16-bit + float64.push_back(ldexp((double)1.f, -1023)); + float64.push_back(-ldexp((double)1.f, -1023)); + // Normalized 64-bit float matching 0 in 16-bit + float64.push_back(ldexp((double)1.f, -100)); + float64.push_back(-ldexp((double)1.f, -100)); + // Normalized 64-bit float with exact normalized match in 16-bit + float64.push_back(ldexp((double)1.f, -14)); // 2e-14: minimum 16-bit positive normalized + float64.push_back(-ldexp((double)1.f, -14)); // 2e-14: maximum 16-bit negative normalized + // Normalized 64-bit float falling above half way within two 16-bit normalized + float64.push_back(bitwiseCast<double>(deUint64(0x3FD2000000000000))); + float64.push_back(bitwiseCast<double>(deUint64(0xBFD2000000000000))); + // Normalized 64-bit float falling exact half way within two 16-bit normalized + float64.push_back(bitwiseCast<double>(deUint64(0x3F100C0000000000))); + float64.push_back(bitwiseCast<double>(deUint64(0xBF100C0000000000))); + // Some number + float64.push_back((double)0.28125f); + float64.push_back((double)-0.28125f); const deUint32 numPicks = static_cast<deUint32>(float64.size()); DE_ASSERT(count >= numPicks); count -= numPicks; - for (deUint32 numNdx = 0; numNdx < count; ++numNdx) + for (deUint32 numNdx = 0; numNdx < count;) { - double randValue = rnd.getDouble(); - float64.push_back(randValue); + double rndFloat = rnd.getDouble(); + // If special float16 values must be excluded, generated double values that result in inf/nan/denormal of float16 should be removed. + if (!includeSpecialFloat16Values) + { + deFloat16 rndFloat16 = deFloat64To16(rndFloat); + if (deHalfIsInf(rndFloat16) || deHalfIsIEEENaN(rndFloat16) || deHalfIsDenormal(rndFloat16)) + continue; + } + float64.push_back(rndFloat); + ++numNdx; } return float64; @@ -558,37 +566,44 @@ std::vector<double> getFloat64s (de::Random& rnd, deUint32 count) // Generate and return 32-bit floats // -// The first 24 number pairs are manually picked, while the rest are randomly generated. -// Expected count to be at least 24 (numPicks). -std::vector<float> getFloat32s (de::Random& rnd, deUint32 count) +// If includeSpecialFloat16Values is false, random float32 that can be converted to float16 inf/nan/denormal must be excluded +// since inf may be clamped, and nan/denormal be flushed without float control features. +// And expected count to be at least 14 (numPicks). +// Otherwise, the first 24 number pairs are manually picked, while the rest are randomly generated. +// And expected count to be at least 24 (numPicks). +std::vector<float> getFloat32s (de::Random& rnd, deUint32 count, deBool includeSpecialFloat16Values) { std::vector<float> float32; float32.reserve(count); + if (includeSpecialFloat16Values) + { + // Infinity + float32.push_back(std::numeric_limits<float>::infinity()); + float32.push_back(-std::numeric_limits<float>::infinity()); + // SNaN + float32.push_back(std::numeric_limits<float>::signaling_NaN()); + float32.push_back(-std::numeric_limits<float>::signaling_NaN()); + // QNaN + float32.push_back(std::numeric_limits<float>::quiet_NaN()); + float32.push_back(-std::numeric_limits<float>::quiet_NaN()); + // Normalized 32-bit float with exact denormalized match in 16-bit + float32.push_back(deFloatLdExp(1.f, -24)); // 2e-24: minimum 16-bit positive denormalized + float32.push_back(-deFloatLdExp(1.f, -24)); // 2e-24: maximum 16-bit negative denormalized + // Normalized 32-bit float matching infinity in 16-bit + float32.push_back(deFloatLdExp(1.f, 100)); + float32.push_back(-deFloatLdExp(1.f, 100)); + } // Zero float32.push_back(0.f); float32.push_back(-0.f); - // Infinity - float32.push_back(std::numeric_limits<float>::infinity()); - float32.push_back(-std::numeric_limits<float>::infinity()); - // SNaN - float32.push_back(std::numeric_limits<float>::signaling_NaN()); - float32.push_back(-std::numeric_limits<float>::signaling_NaN()); - // QNaN - float32.push_back(std::numeric_limits<float>::quiet_NaN()); - float32.push_back(-std::numeric_limits<float>::quiet_NaN()); - // Denormalized 32-bit float matching 0 in 16-bit float32.push_back(deFloatLdExp(1.f, -127)); float32.push_back(-deFloatLdExp(1.f, -127)); - // Normalized 32-bit float matching 0 in 16-bit float32.push_back(deFloatLdExp(1.f, -100)); float32.push_back(-deFloatLdExp(1.f, -100)); - // Normalized 32-bit float with exact denormalized match in 16-bit - float32.push_back(deFloatLdExp(1.f, -24)); // 2e-24: minimum 16-bit positive denormalized - float32.push_back(-deFloatLdExp(1.f, -24)); // 2e-24: maximum 16-bit negative denormalized // Normalized 32-bit float with exact normalized match in 16-bit float32.push_back(deFloatLdExp(1.f, -14)); // 2e-14: minimum 16-bit positive normalized float32.push_back(-deFloatLdExp(1.f, -14)); // 2e-14: maximum 16-bit negative normalized @@ -601,17 +616,26 @@ std::vector<float> getFloat32s (de::Random& rnd, deUint32 count) // Some number float32.push_back(0.28125f); float32.push_back(-0.28125f); - // Normalized 32-bit float matching infinity in 16-bit - float32.push_back(deFloatLdExp(1.f, 100)); - float32.push_back(-deFloatLdExp(1.f, 100)); const deUint32 numPicks = static_cast<deUint32>(float32.size()); DE_ASSERT(count >= numPicks); count -= numPicks; - for (deUint32 numNdx = 0; numNdx < count; ++numNdx) - float32.push_back(rnd.getFloat()); + for (deUint32 numNdx = 0; numNdx < count;) + { + float rndFloat = rnd.getFloat(); + // If special float16 values must be excluded, generated float values that result in inf/nan/denormal of float16 should be removed. + if (!includeSpecialFloat16Values) + { + deFloat16 rndFloat16 = deFloat32To16(rndFloat); + if (deHalfIsInf(rndFloat16) || deHalfIsIEEENaN(rndFloat16) || deHalfIsDenormal(rndFloat16)) + continue; + } + + float32.push_back(rndFloat); + ++numNdx; + } return float32; } @@ -638,32 +662,36 @@ std::vector<float> getFloat32s (de::Random& rnd, deUint32 count) // 0 111 11 00 0000 1111 (0x7c0f: +SNaN) // 0 111 11 00 1111 0000 (0x7c0f: +QNaN) -// Generate and return 16-bit floats and their corresponding 32-bit values. +// Generate and return 16-bit floats // -// The first 14 number pairs are manually picked, while the rest are randomly generated. -// Expected count to be at least 14 (numPicks). -std::vector<deFloat16> getFloat16s (de::Random& rnd, deUint32 count) +// If includeSpecialFloat16Values is false, float16 inf/nan/denormal must be excluded since inf may be clamped, +// and nan/denormal be flushed without float control features. And expected count to be at least 6 (numPicks). +// Otherwise, the first 14 number pairs are manually picked, while the rest are randomly generated. +// And expected count to be at least 14 (numPicks). +std::vector<deFloat16> getFloat16s (de::Random& rnd, deUint32 count, deBool includeSpecialFloat16Values) { std::vector<deFloat16> float16; float16.reserve(count); + if (includeSpecialFloat16Values) + { + // Infinity + float16.push_back(deUint16(0x7c00)); + float16.push_back(deUint16(0xfc00)); + // SNaN + float16.push_back(deUint16(0x7c0f)); + float16.push_back(deUint16(0xfc0f)); + // QNaN + float16.push_back(deUint16(0x7cf0)); + float16.push_back(deUint16(0xfcf0)); + // Denormalized + float16.push_back(deUint16(0x03f0)); + float16.push_back(deUint16(0x83f0)); + } // Zero float16.push_back(deUint16(0x0000)); float16.push_back(deUint16(0x8000)); - // Infinity - float16.push_back(deUint16(0x7c00)); - float16.push_back(deUint16(0xfc00)); - // SNaN - float16.push_back(deUint16(0x7c0f)); - float16.push_back(deUint16(0xfc0f)); - // QNaN - float16.push_back(deUint16(0x7cf0)); - float16.push_back(deUint16(0xfcf0)); - - // Denormalized - float16.push_back(deUint16(0x03f0)); - float16.push_back(deUint16(0x83f0)); // Normalized float16.push_back(deUint16(0x0401)); float16.push_back(deUint16(0x8401)); @@ -676,8 +704,15 @@ std::vector<deFloat16> getFloat16s (de::Random& rnd, deUint32 count) DE_ASSERT(count >= numPicks); count -= numPicks; - for (deUint32 numIdx = 0; numIdx < count; ++numIdx) - float16.push_back(rnd.getUint16()); + for (deUint32 numIdx = 0; numIdx < count;) + { + deFloat16 rndFloat = rnd.getUint16(); + // If special float16 values must be excluded, generated values in inf/nan/denormal should be removed. + if (!includeSpecialFloat16Values && (deHalfIsInf(rndFloat) || deHalfIsIEEENaN(rndFloat) || deHalfIsDenormal(rndFloat))) + continue; + float16.push_back(rndFloat); + ++numIdx; + } return float16; } diff --git a/external/vulkancts/modules/vulkan/spirv_assembly/vktSpvAsmUtils.hpp b/external/vulkancts/modules/vulkan/spirv_assembly/vktSpvAsmUtils.hpp index c40938d46..313803e80 100644 --- a/external/vulkancts/modules/vulkan/spirv_assembly/vktSpvAsmUtils.hpp +++ b/external/vulkancts/modules/vulkan/spirv_assembly/vktSpvAsmUtils.hpp @@ -306,21 +306,29 @@ std::vector<deInt8> getInt8s (de::Random& rnd, const deUint32 count); // Generate and return 64-bit floats // -// The first 24 number pairs are manually picked, while the rest are randomly generated. -// Expected count to be at least 24 (numPicks). -std::vector<double> getFloat64s (de::Random& rnd, deUint32 count); +// If includeSpecialFloat16Values is false, random float64 that can be converted to float16 inf/nan/denormal must be excluded +// since inf may be clamped, and nan/denormal be flushed without float control features. +// And expected count to be at least 14 (numPicks). +// Otherwise, the first 24 number pairs are manually picked, while the rest are randomly generated. +// And expected count to be at least 24 (numPicks). +std::vector<double> getFloat64s (de::Random& rnd, deUint32 count, deBool includeSpecialFloat16Values = DE_TRUE); // Generate and return 32-bit floats // -// The first 24 number pairs are manually picked, while the rest are randomly generated. -// Expected count to be at least 24 (numPicks). -std::vector<float> getFloat32s (de::Random& rnd, deUint32 count); - -// Generate and return 16-bit floats and their corresponding 32-bit values. +// If includeSpecialFloat16Values is false, random float32 that can be converted to float16 inf/nan/denormal must be excluded +// since inf may be clamped, and nan/denormal be flushed without float control features. +// And expected count to be at least 14 (numPicks). +// Otherwise, the first 24 number pairs are manually picked, while the rest are randomly generated. +// And expected count to be at least 24 (numPicks). +std::vector<float> getFloat32s (de::Random& rnd, deUint32 count, deBool includeSpecialFloat16Values = DE_TRUE); + +// Generate and return 16-bit floats // -// The first 14 number pairs are manually picked, while the rest are randomly generated. -// Expected count to be at least 14 (numPicks). -std::vector<deFloat16> getFloat16s (de::Random& rnd, deUint32 count); +// If includeSpecialFloat16Values is false, float16 inf/nan/denormal must be excluded since inf may be clamped, +// and nan/denormal be flushed without float control features. And expected count to be at least 6 (numPicks). +// Otherwise, the first 14 number pairs are manually picked, while the rest are randomly generated. +// And expected count to be at least 14 (numPicks). +std::vector<deFloat16> getFloat16s (de::Random& rnd, deUint32 count, deBool includeSpecialFloat16Values = DE_TRUE); // Generate an OpCapability Shader line. std::string getOpCapabilityShader(); diff --git a/framework/delibs/debase/deFloat16.h b/framework/delibs/debase/deFloat16.h index 4b25c842b..1857ef779 100644 --- a/framework/delibs/debase/deFloat16.h +++ b/framework/delibs/debase/deFloat16.h @@ -60,14 +60,41 @@ float deFloat16To32 (deFloat16 val16); *//*--------------------------------------------------------------------*/ double deFloat16To64 (deFloat16 val16); +DE_INLINE deUint16 deHalfExponent(deFloat16 x) +{ + return (deUint16)((x & 0x7c00u) >> 10); +} + +DE_INLINE deUint16 deHalfMantissa(deFloat16 x) +{ + return (deUint16)(x & 0x03ffu); +} + +DE_INLINE deUint16 deHalfHighestMantissaBit(deFloat16 x) +{ + return (deUint16)(x & (1u << 9)); +} + +DE_INLINE deUint16 deHalfSign(deFloat16 x) +{ + return (deUint16)(x >> 15); +} + +static const deUint16 deHalfMaxExponent = 0x1f; + +DE_INLINE deBool deHalfIsZero(deFloat16 x) +{ + return deHalfExponent(x) == 0 && deHalfMantissa(x) == 0; +} + DE_INLINE deBool deHalfIsPositiveZero(deFloat16 x) { - return deFloat16To32(x) == 0 && (x >> 15) == 0; + return deHalfIsZero(x) && (deHalfSign(x) == 0); } DE_INLINE deBool deHalfIsNegativeZero(deFloat16 x) { - return deFloat16To32(x) == 0 && (x >> 15) != 0; + return deHalfIsZero(x) && (deHalfSign(x) != 0); } static const deFloat16 deFloat16SignalingNaN = 0x7c01; @@ -75,19 +102,37 @@ static const deFloat16 deFloat16QuietNaN = 0x7e01; DE_INLINE deBool deHalfIsIEEENaN(deFloat16 x) { - deUint16 e = (deUint16)((x & 0x7c00u) >> 10); - deUint16 m = (x & 0x03ffu); - return e == 0x1f && m != 0; + return deHalfExponent(x) == deHalfMaxExponent && deHalfMantissa(x) != 0; } DE_INLINE deBool deHalfIsSignalingNaN(deFloat16 x) { - return deHalfIsIEEENaN(x) && (x & (1u << 9)) == 0; + return deHalfIsIEEENaN(x) && deHalfHighestMantissaBit(x) == 0; } DE_INLINE deBool deHalfIsQuietNaN(deFloat16 x) { - return deHalfIsIEEENaN(x) && (x & (1u << 9)) != 0; + return deHalfIsIEEENaN(x) && deHalfHighestMantissaBit(x) != 0; +} + +DE_INLINE deBool deHalfIsInf(deFloat16 x) +{ + return deHalfExponent(x) == deHalfMaxExponent && deHalfMantissa(x) == 0; +} + +DE_INLINE deBool deHalfIsPositiveInf(deFloat16 x) +{ + return deHalfIsInf(x) && (deHalfSign(x) == 0); +} + +DE_INLINE deBool deHalfIsNegativeInf(deFloat16 x) +{ + return deHalfIsInf(x) && (deHalfSign(x) != 0); +} + +DE_INLINE deBool deHalfIsDenormal(deFloat16 x) +{ + return deHalfExponent(x) == 0 && deHalfMantissa(x) != 0; } DE_END_EXTERN_C |