[Mesa-dev] [PATCH 01/11] glsl/lower_instruction: handle denorms and overflow in ldexp correctly

Nicolai Hähnle nhaehnle at gmail.com
Fri Sep 29 10:06:46 UTC 2017


On 29.09.2017 00:54, Matt Turner wrote:
> On Sat, Sep 16, 2017 at 4:23 AM, Nicolai Hähnle <nhaehnle at gmail.com> wrote:
>> From: Nicolai Hähnle <nicolai.haehnle at amd.com>
>>
>> GLSL ES requires both, and while GLSL explicitly doesn't require correct
>> overflow handling, it does appear to require handling input inf/denorms
>> correctly.
>>
>> Fixes dEQP-GLES31.functional.shaders.builtin_functions.precision.ldexp.*
>>
>> Cc: mesa-stable at lists.freedesktop.org
>> ---
>>   src/compiler/glsl/lower_instructions.cpp | 171 +++++++++++++++++++------------
>>   1 file changed, 107 insertions(+), 64 deletions(-)
>>
>> diff --git a/src/compiler/glsl/lower_instructions.cpp b/src/compiler/glsl/lower_instructions.cpp
>> index 0c1408911d2..362562a4af6 100644
>> --- a/src/compiler/glsl/lower_instructions.cpp
>> +++ b/src/compiler/glsl/lower_instructions.cpp
>> @@ -358,140 +358,183 @@ lower_instructions_visitor::mod_to_floor(ir_expression *ir)
>>   }
>>
>>   void
>>   lower_instructions_visitor::ldexp_to_arith(ir_expression *ir)
>>   {
>>      /* Translates
>>       *    ir_binop_ldexp x exp
>>       * into
>>       *
>>       *    extracted_biased_exp = rshift(bitcast_f2i(abs(x)), exp_shift);
>> -    *    resulting_biased_exp = extracted_biased_exp + exp;
>> +    *    resulting_biased_exp = min(extracted_biased_exp + exp, 255);
>>       *
>> -    *    if (resulting_biased_exp < 1 || x == 0.0f) {
>> -    *       return copysign(0.0, x);
>> +    *    if (extracted_biased_exp >= 255)
>> +    *       return x; // +/-inf, NaN
>> +    *
>> +    *    sign_mantissa = bitcast_f2u(x) & sign_mantissa_mask;
>> +    *
>> +    *    if (min(resulting_biased_exp, extracted_biased_exp) < 1)
>> +    *       resulting_biased_exp = 0;
>> +    *    if (resulting_biased_exp >= 255 ||
>> +    *        min(resulting_biased_exp, extracted_biased_exp) < 1) {
>> +    *       sign_mantissa &= sign_mask;
>>       *    }
>>       *
>> -    *    return bitcast_u2f((bitcast_f2u(x) & sign_mantissa_mask) |
>> +    *    return bitcast_u2f(sign_mantissa |
>>       *                       lshift(i2u(resulting_biased_exp), exp_shift));
>>       *
>>       * which we can't actually implement as such, since the GLSL IR doesn't
>>       * have vectorized if-statements. We actually implement it without branches
>>       * using conditional-select:
>>       *
>>       *    extracted_biased_exp = rshift(bitcast_f2i(abs(x)), exp_shift);
>> -    *    resulting_biased_exp = extracted_biased_exp + exp;
>> +    *    resulting_biased_exp = min(extracted_biased_exp + exp, 255);
>>       *
>> -    *    is_not_zero_or_underflow = logic_and(nequal(x, 0.0f),
>> -    *                                         gequal(resulting_biased_exp, 1);
>> -    *    x = csel(is_not_zero_or_underflow, x, copysign(0.0f, x));
>> -    *    resulting_biased_exp = csel(is_not_zero_or_underflow,
>> -    *                                resulting_biased_exp, 0);
>> +    *    sign_mantissa = bitcast_f2u(x) & sign_mantissa_mask;
>>       *
>> -    *    return bitcast_u2f((bitcast_f2u(x) & sign_mantissa_mask) |
>> -    *                       lshift(i2u(resulting_biased_exp), exp_shift));
>> +    *    flush_to_zero = lequal(min(resulting_biased_exp, extracted_biased_exp), 0);
>> +    *    resulting_biased_exp = csel(flush_to_zero, 0, resulting_biased_exp)
>> +    *    zero_mantissa = logic_or(flush_to_zero,
>> +    *                             gequal(resulting_biased_exp, 255));
>> +    *    sign_mantissa = csel(zero_mantissa, sign_mantissa & sign_mask, sign_mantissa);
>> +    *
>> +    *    result = sign_mantissa |
>> +    *             lshift(i2u(resulting_biased_exp), exp_shift));
>> +    *
>> +    *    return csel(extracted_biased_exp >= 255, x, bitcast_u2f(result));
>> +    *
>> +    * The definition of ldexp in the GLSL spec says:
>> +    *
>> +    *    "If this product is too large to be represented in the
>> +    *     floating-point type, the result is undefined."
>> +    *
>> +    * However, the definition of ldexp in the GLSL ES spec does not contain
>> +    * this sentence, so we do need to handle overflow correctly.
> 
> Without contradictory evidence, I would expect that was an oversight
> and that it's also undefined in GLSL ES.
> 
> Is this required to fix the dEQP test you mention? If it's actually
> spec'd to behave differently between desktop and ES then that's really
> embarrassing.

Yes, it is, and yes, it is...


> 
> As mentioned, you may want to just replace this whole lowering pass
> with what Jason's done in nir_opt_algebraic.py for ldexp.
> 
> Whatever you decide to do, this patch is:
> 
> Acked-by: Matt Turner <mattst88 at gmail.com>

Thanks.

Cheers,
Nicolai


-- 
Lerne, wie die Welt wirklich ist,
Aber vergiss niemals, wie sie sein sollte.


More information about the mesa-dev mailing list