Permit not flushing operands for FP16 DenormFlushToZero add, dot, vmulm
authorAndrea Faulds <andrea.faulds@arm.com>
Thu, 5 Nov 2020 15:35:51 +0000 (16:35 +0100)
committerAndrea Faulds <andrea.faulds@arm.com>
Thu, 5 Nov 2020 15:35:51 +0000 (16:35 +0100)
Where `d` is a denormal value such that `2 * d` is not denormal:

- The F16 OpFAdd tests assumed (d + d) is zero when DenormFlushToZero is
  used. This is not true if the operands (d) are not flushed to zero by
  the implementation, which is allowed by the Vulkan specification.
- The F16 OpDot test assumed dot(vec2(d, d), vec2(1, 1)) is zero. Since
  that is equivalent to (d + d), it has the same problem as OpFAdd.
- The F16 OpVectorTimesMatrix test made the same assumption as the OpDot
  test but for both columns of a 2-by-2 matrix, with the same problem.

These tests are changed to accept `2 * d` as a valid result alongside
zero, such that they will pass both on implementations which flush
operands to zero and on implementations which only flush results to
zero.

Modified tests:

    dEQP-VK.spirv_assembly.instruction.*.float_controls.fp16.input_args.denorm_*flush_to_zero*
    dEQP-VK.spirv_assembly.instruction.compute.float_controls.independence_settings.denorm_ind_*_fp16_flush_*

VK-GL-CTS Issue: 2644

Components: Vulkan

Change-Id: I0ef4a57915e3bdab100f55f52d21913f87af4927

external/vulkancts/modules/vulkan/spirv_assembly/vktSpvAsmFloatControlsTests.cpp

index 97697e3bee8555c68c53d65547ae1d41f12deefc..24ff0f625bbecc645f0d14e2d9972b8bccffc343 100644 (file)
@@ -144,7 +144,8 @@ enum ValueId
        V_DOT_RTE_RESULT,
 
        // non comon results of some operation - corner cases
-       V_MINUS_ONE_OR_CLOSE,                   // value used only fur fp16 subtraction result of preserved denorm and one
+       V_ZERO_OR_DENORM_TIMES_TWO,             // fp16 addition of non-flushed denorm with itself (or equivalent dot-product or vector-matrix multiply)
+       V_MINUS_ONE_OR_CLOSE,                   // value used only for 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
@@ -967,19 +968,22 @@ TypeTestResults<deFloat16>::TypeTestResults()
        // to those that return denorm as those are the ones affected by tested extension
        const BinaryCase binaryOpFTZArr[] = {
                //operation             den op one              den op den              den op inf              den op nan
-               { O_ADD,                V_ONE,                  V_ZERO,                 V_INF,                  V_UNUSED },
+               { O_ADD,                V_ONE,                  V_ZERO_OR_DENORM_TIMES_TWO,
+                                                                                                               V_INF,                  V_UNUSED },
                { O_SUB,                V_MINUS_ONE,    V_ZERO,                 V_MINUS_INF,    V_UNUSED },
                { O_MUL,                V_ZERO,                 V_ZERO,                 V_UNUSED,               V_UNUSED },
                { O_DIV,                V_ZERO,                 V_UNUSED,               V_ZERO,                 V_UNUSED },
                { O_REM,                V_ZERO,                 V_UNUSED,               V_UNUSED,               V_UNUSED },
                { O_MOD,                V_ZERO,                 V_UNUSED,               V_UNUSED,               V_UNUSED },
                { O_VEC_MUL_S,  V_ZERO,                 V_ZERO,                 V_UNUSED,               V_UNUSED },
-               { O_VEC_MUL_M,  V_ZERO,                 V_ZERO,                 V_UNUSED,               V_UNUSED },
+               { O_VEC_MUL_M,  V_ZERO_OR_DENORM_TIMES_TWO,
+                                                                               V_ZERO,                 V_UNUSED,               V_UNUSED },
                { O_MAT_MUL_S,  V_ZERO,                 V_ZERO,                 V_UNUSED,               V_UNUSED },
                { O_MAT_MUL_V,  V_ZERO,                 V_ZERO,                 V_UNUSED,               V_UNUSED },
                { O_MAT_MUL_M,  V_ZERO,                 V_ZERO,                 V_UNUSED,               V_UNUSED },
                { O_OUT_PROD,   V_ZERO,                 V_ZERO,                 V_UNUSED,               V_UNUSED },
-               { O_DOT,                V_ZERO,                 V_ZERO,                 V_UNUSED,               V_UNUSED },
+               { O_DOT,                V_ZERO_OR_DENORM_TIMES_TWO,
+                                                                               V_ZERO,                 V_UNUSED,               V_UNUSED },
                { O_ATAN2,              V_ZERO,                 V_UNUSED,               V_ZERO,                 V_UNUSED },
                { O_POW,                V_ZERO,                 V_UNUSED,               V_ZERO,                 V_UNUSED },
                { O_MIX,                V_HALF,                 V_ZERO,                 V_INF,                  V_UNUSED },
@@ -2505,6 +2509,12 @@ bool compareBytes(vector<deUint8>& expectedBytes, AllocationSp outputAlloc, Test
                return isZeroOrOtherValue<TYPE, FLOAT_TYPE>(returnedFloat, V_CONV_DENORM_SMALLER, log);
        if (expectedValueId == V_ZERO_OR_FP32_DENORM_TO_FP64)
                return isZeroOrOtherValue<TYPE, FLOAT_TYPE>(returnedFloat, V_CONV_DENORM_BIGGER, log);
+       if (expectedValueId == V_ZERO_OR_DENORM_TIMES_TWO)
+       {
+               // this expected value is only needed for fp16
+               DE_ASSERT(returnedFloat.EXPONENT_BIAS == 15);
+               return isZeroOrOtherValue<TYPE, FLOAT_TYPE>(returnedFloat, V_DENORM_TIMES_TWO, log);
+       }
        if (expectedValueId == V_MINUS_ONE_OR_CLOSE)
        {
                // this expected value is only needed for fp16
@@ -3436,7 +3446,7 @@ void ComputeTestGroupBuilder::fillShaderSpec(const SettingsTestCaseInfo&  testCas
 
                addArgs[0]                                      = V_DENORM;
                addArgs[1]                                      = V_DENORM;
-               fp16resultValue                         = fp16DenormPreserve ? V_DENORM_TIMES_TWO : V_ZERO;
+               fp16resultValue                         = fp16DenormPreserve ? V_DENORM_TIMES_TWO : V_ZERO_OR_DENORM_TIMES_TWO;
                fp32resultValue                         = fp32DenormPreserve ? V_DENORM_TIMES_TWO : V_ZERO;
                fp64resultValue                         = fp64DenormPreserve ? V_DENORM_TIMES_TWO : V_ZERO;