diff --git a/src/compiler/nir/nir_builtin_builder.c b/src/compiler/nir/nir_builtin_builder.c index da332e72de9..b975157cfb1 100644 --- a/src/compiler/nir/nir_builtin_builder.c +++ b/src/compiler/nir/nir_builtin_builder.c @@ -223,7 +223,28 @@ nir_atan(nir_builder *b, nir_ssa_def *y_over_x) tmp); /* sign fixup */ - return nir_fmul(b, tmp, nir_fsign(b, y_over_x)); + nir_ssa_def *result = nir_fmul(b, tmp, nir_fsign(b, y_over_x)); + + /* The fmin and fmax above will filter out NaN values. This leads to + * non-NaN results for NaN inputs. Work around this by doing + * + * !isnan(y_over_x) ? ... : y_over_x; + */ + if (b->exact || + nir_is_float_control_signed_zero_inf_nan_preserve(b->shader->info.float_controls_execution_mode, bit_size)) { + const bool exact = b->exact; + + b->exact = true; + nir_ssa_def *is_not_nan = nir_feq(b, y_over_x, y_over_x); + b->exact = exact; + + /* The extra 1.0*y_over_x ensures that subnormal results are flushed to + * zero. + */ + result = nir_bcsel(b, is_not_nan, result, nir_fmul_imm(b, y_over_x, 1.0)); + } + + return result; } nir_ssa_def *