From 1ac379c4a085801440087bd47af6029700e7c58a Mon Sep 17 00:00:00 2001 From: =?utf8?q?Marek=20Ol=C5=A1=C3=A1k?= Date: Sat, 8 Jul 2023 17:09:15 -0400 Subject: [PATCH] nir/algebraic: collapse ALU opcodes sourcing NaN Undef will be replaced by NaN whenever it leads to elimination of FP instructions. This implements the elimination part. Reviewed-by: Faith Ekstrand Part-of: --- src/compiler/nir/nir_opt_algebraic.py | 43 +++++++++++++++++++++++++++++++++++ src/compiler/nir/nir_search_helpers.h | 32 ++++++++++++++++++++++++++ 2 files changed, 75 insertions(+) diff --git a/src/compiler/nir/nir_opt_algebraic.py b/src/compiler/nir/nir_opt_algebraic.py index a430aa1..030ac6e 100644 --- a/src/compiler/nir/nir_opt_algebraic.py +++ b/src/compiler/nir/nir_opt_algebraic.py @@ -35,6 +35,7 @@ b = 'b' c = 'c' d = 'd' e = 'e' +NAN = math.nan signed_zero_inf_nan_preserve_16 = 'nir_is_float_control_signed_zero_inf_nan_preserve(info->float_controls_execution_mode, 16)' signed_zero_inf_nan_preserve_32 = 'nir_is_float_control_signed_zero_inf_nan_preserve(info->float_controls_execution_mode, 32)' @@ -2757,6 +2758,48 @@ for s in range(0, 31): 'options->avoid_ternary_with_two_constants'), ]) +# NaN propagation: Binary opcodes. If any operand is NaN, replace it with NaN. +# (unary opcodes with NaN are evaluated by nir_opt_constant_folding, not here) +for op in ['fadd', 'fdiv', 'fmod', 'fmul', 'fpow', 'frem', 'fsub']: + optimizations += [((op, '#a(is_nan)', b), NAN)] + optimizations += [((op, a, '#b(is_nan)'), NAN)] # some opcodes are not commutative + +# NaN propagation: Trinary opcodes. If any operand is NaN, replace it with NaN. +for op in ['ffma', 'flrp']: + optimizations += [((op, '#a(is_nan)', b, c), NAN)] + optimizations += [((op, a, '#b(is_nan)', c), NAN)] # some opcodes are not commutative + optimizations += [((op, a, b, '#c(is_nan)'), NAN)] + +# NaN propagation: FP min/max. Pick the non-NaN operand. +for op in ['fmin', 'fmax']: + optimizations += [((op, '#a(is_nan)', b), b)] # commutative + +# NaN propagation: ldexp is NaN if the first operand is NaN. +optimizations += [(('ldexp', '#a(is_nan)', b), NAN)] + +# NaN propagation: Dot opcodes. If any component is NaN, replace it with NaN. +for op in ['fdot2', 'fdot3', 'fdot4', 'fdot5', 'fdot8', 'fdot16']: + optimizations += [((op, '#a(is_any_comp_nan)', b), NAN)] # commutative + +# NaN propagation: FP comparison opcodes except !=. Replace it with false. +for op in ['feq', 'fge', 'flt']: + optimizations += [((op, '#a(is_nan)', b), False)] + optimizations += [((op, a, '#b(is_nan)'), False)] # some opcodes are not commutative + +# NaN propagation: FP comparison opcodes using !=. Replace it with true. +# Operator != is the only opcode where a comparison with NaN returns true. +for op in ['fneu']: + optimizations += [((op, '#a(is_nan)', b), True)] # commutative + +# NaN propagation: FP comparison opcodes except != returning FP 0 or 1. +for op in ['seq', 'sge', 'slt']: + optimizations += [((op, '#a(is_nan)', b), 0.0)] + optimizations += [((op, a, '#b(is_nan)'), 0.0)] # some opcodes are not commutative + +# NaN propagation: FP comparison opcodes using != returning FP 0 or 1. +# Operator != is the only opcode where a comparison with NaN returns true. +optimizations += [(('sne', '#a(is_nan)', b), 1.0)] # commutative + # This section contains optimizations to propagate downsizing conversions of # constructed vectors into vectors of downsized components. Whether this is # useful depends on the SIMD semantics of the backend. On a true SIMD machine, diff --git a/src/compiler/nir/nir_search_helpers.h b/src/compiler/nir/nir_search_helpers.h index 32c1f88..809c257 100644 --- a/src/compiler/nir/nir_search_helpers.h +++ b/src/compiler/nir/nir_search_helpers.h @@ -111,6 +111,38 @@ is_bitcount2(UNUSED struct hash_table *ht, const nir_alu_instr *instr, return true; } +static inline bool +is_nan(UNUSED struct hash_table *ht, const nir_alu_instr *instr, + unsigned src, unsigned num_components, const uint8_t *swizzle) +{ + /* only constant srcs: */ + if (!nir_src_is_const(instr->src[src].src)) + return false; + + for (unsigned i = 0; i < num_components; i++) { + if (!isnan(nir_src_comp_as_float(instr->src[src].src, swizzle[i]))) + return false; + } + + return true; +} + +static inline bool +is_any_comp_nan(UNUSED struct hash_table *ht, const nir_alu_instr *instr, + unsigned src, unsigned num_components, const uint8_t *swizzle) +{ + /* only constant srcs: */ + if (!nir_src_is_const(instr->src[src].src)) + return false; + + for (unsigned i = 0; i < num_components; i++) { + if (isnan(nir_src_comp_as_float(instr->src[src].src, swizzle[i]))) + return true; + } + + return false; +} + #define MULTIPLE(test) \ static inline bool \ is_unsigned_multiple_of_##test(UNUSED struct hash_table *ht, \ -- 2.7.4