If one of the inputs to and mul/add is the result of an another mul/add there is a chance that we can reuse the result of that mul/add in other calls if we do the multiplication in the right order.
Also by attempting to move all constants to the top we increase the chance of constant folding. For example it is a fairly common pattern for shaders to do something similar to this: const float a = 0.5; in vec4 b; in float c; ... b.x = b.x * c; b.y = b.y * c; ... b.x = b.x * a + a; b.y = b.y * a + a; So by simply detecting that constant a is part of the multiplication in ffma and switching it with previous fmul that updates b we end up with: ... c = a * c; ... b.x = b.x * c + a; b.y = b.y * c + a; Shader-db results BDW: total instructions in shared programs: 13007456 -> 12964294 (-0.33%) instructions in affected programs: 4117749 -> 4074587 (-1.05%) helped: 17740 HURT: 1342 total cycles in shared programs: 246765094 -> 246454280 (-0.13%) cycles in affected programs: 167300168 -> 166989354 (-0.19%) helped: 18541 HURT: 7955 total spills in shared programs: 14937 -> 14560 (-2.52%) spills in affected programs: 9331 -> 8954 (-4.04%) helped: 284 HURT: 33 total fills in shared programs: 20211 -> 19671 (-2.67%) fills in affected programs: 12586 -> 12046 (-4.29%) helped: 286 HURT: 33 LOST: 40 GAINED: 34 Some of the hurt will go away when we shuffle things back down to the bottom in the following patch. It's also noteworthy that almost all of the spill changes as in Deus Ex both hurt and helped. --- src/compiler/nir/nir_opt_algebraic.py | 8 +++++++- src/compiler/nir/nir_search_helpers.h | 12 ++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/compiler/nir/nir_opt_algebraic.py b/src/compiler/nir/nir_opt_algebraic.py index 2c8ad64..797fc4b 100644 --- a/src/compiler/nir/nir_opt_algebraic.py +++ b/src/compiler/nir/nir_opt_algebraic.py @@ -326,8 +326,14 @@ optimizations = [ (('fmul', ('fneg', a), b), ('fneg', ('fmul', a, b))), (('imul', ('ineg', a), b), ('ineg', ('imul', a, b))), + # Propagate constants up multiplication chains + (('fmul(is_used_once)', ('fmul(is_used_once)', 'a(is_not_const)', 'b(is_not_const)'), '#c'), ('fmul', ('fmul', a, c), b)), + (('imul(is_used_once)', ('imul(is_used_once)', 'a(is_not_const)', 'b(is_not_const)'), '#c'), ('imul', ('imul', a, c), b)), + (('fadd(is_used_once)', ('fadd(is_used_once)', 'a(is_not_const)', 'b(is_not_const)'), '#c'), ('fadd', ('fadd', a, c), b)), + (('iadd(is_used_once)', ('iadd(is_used_once)', 'a(is_not_const)', 'b(is_not_const)'), '#c'), ('iadd', ('iadd', a, c), b)), + # Reassociate constants in add/mul chains so they can be folded together. - # For now, we only handle cases where the constants are separated by + # For now, we mostly only handle cases where the constants are separated by # a single non-constant. We could do better eventually. (('~fmul', '#a', ('fmul', b, '#c')), ('fmul', ('fmul', a, c), b)), (('imul', '#a', ('imul', b, '#c')), ('imul', ('imul', a, c), b)), diff --git a/src/compiler/nir/nir_search_helpers.h b/src/compiler/nir/nir_search_helpers.h index 05bd317..09ae137 100644 --- a/src/compiler/nir/nir_search_helpers.h +++ b/src/compiler/nir/nir_search_helpers.h @@ -115,6 +115,18 @@ is_zero_to_one(nir_alu_instr *instr, unsigned src, unsigned num_components, } static inline bool +is_not_const(nir_alu_instr *instr, unsigned src, unsigned num_components, + const uint8_t *swizzle) +{ + nir_const_value *val = nir_src_as_const_value(instr->src[src].src); + + if (val) + return false; + + return true; +} + +static inline bool is_used_more_than_once(nir_alu_instr *instr) { bool zero_if_use = list_empty(&instr->dest.dest.ssa.if_uses); -- 2.9.3 _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/mesa-dev