nir: add lower_fminmax_signed_zero

This implements IEEE-754-2019 signed zero semantics for fmin/fmax, as now
required by NIR, for hardware that has busted signed zero behaviour for
fmin/fmax. Ian expressed interest in this for Intel.

Signed-off-by: Alyssa Rosenzweig <alyssa@rosenzweig.io>
Reviewed-by: Ian Romanick <ian.d.romanick@intel.com>
Reviewed-by: Konstantin Seurer <konstantin.seurer@gmail.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/30075>
This commit is contained in:
Alyssa Rosenzweig 2024-07-08 14:21:22 -04:00 committed by Marge Bot
parent 0e46f7b39a
commit d238d766c6
2 changed files with 32 additions and 1 deletions

View file

@ -3807,6 +3807,12 @@ typedef struct nir_shader_compiler_options {
/** enable rules that avoid generating umin from signed integer ops */ /** enable rules that avoid generating umin from signed integer ops */
bool lower_umin; bool lower_umin;
/* lower fmin/fmax with signed zero preserve to fmin/fmax with
* no_signed_zero, for backends whose fmin/fmax implementations do not
* implement IEEE-754-2019 semantics for signed zero.
*/
bool lower_fminmax_signed_zero;
/* lower fdph to fdot4 */ /* lower fdph to fdot4 */
bool lower_fdph; bool lower_fdph;

View file

@ -212,6 +212,30 @@ lower_alu_instr(nir_builder *b, nir_instr *instr_, UNUSED void *cb_data)
} }
break; break;
case nir_op_fmin:
case nir_op_fmax: {
if (!b->shader->options->lower_fminmax_signed_zero ||
!nir_alu_instr_is_signed_zero_preserve(instr))
break;
nir_def *s0 = nir_ssa_for_alu_src(b, instr, 0);
nir_def *s1 = nir_ssa_for_alu_src(b, instr, 1);
bool max = instr->op == nir_op_fmax;
nir_def *iminmax = max ? nir_imax(b, s0, s1) : nir_imin(b, s0, s1);
/* Lower the fmin/fmax to a no_signed_zero fmin/fmax. This ensures that
* nir_lower_alu is idempotent, and allows the backend to implement
* soundly the no_signed_zero subset of fmin/fmax.
*/
b->fp_fast_math &= ~FLOAT_CONTROLS_SIGNED_ZERO_PRESERVE;
nir_def *fminmax = max ? nir_fmax(b, s0, s1) : nir_fmin(b, s0, s1);
b->fp_fast_math = instr->fp_fast_math;
lowered = nir_bcsel(b, nir_feq(b, s0, s1), iminmax, fminmax);
break;
}
default: default:
break; break;
} }
@ -229,7 +253,8 @@ nir_lower_alu(nir_shader *shader)
{ {
if (!shader->options->lower_bitfield_reverse && if (!shader->options->lower_bitfield_reverse &&
!shader->options->lower_bit_count && !shader->options->lower_bit_count &&
!shader->options->lower_mul_high) !shader->options->lower_mul_high &&
!shader->options->lower_fminmax_signed_zero)
return false; return false;
return nir_shader_instructions_pass(shader, lower_alu_instr, return nir_shader_instructions_pass(shader, lower_alu_instr,