summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/compiler/nir/nir_opt_algebraic.py12
-rw-r--r--src/compiler/nir/nir_search_helpers.h24
2 files changed, 36 insertions, 0 deletions
diff --git a/src/compiler/nir/nir_opt_algebraic.py b/src/compiler/nir/nir_opt_algebraic.py
index fa940429281..09eaeaf3f23 100644
--- a/src/compiler/nir/nir_opt_algebraic.py
+++ b/src/compiler/nir/nir_opt_algebraic.py
@@ -1250,6 +1250,18 @@ late_optimizations = [
(('fmax', ('fadd(is_used_once)', '#c', a), ('fadd(is_used_once)', '#c', b)), ('fadd', c, ('fmax', a, b))),
(('bcsel', a, 0, ('b2f32', ('inot', 'b@bool'))), ('b2f32', ('inot', ('ior', a, b)))),
+
+ # Things that look like DPH in the source shader may get expanded to
+ # something that looks like dot(v1.xyz, v2.xyz) + v1.w by the time it gets
+ # to NIR. After FFMA is generated, this can look like:
+ #
+ # fadd(ffma(v1.z, v2.z, ffma(v1.y, v2.y, fmul(v1.x, v2.x))), v1.w)
+ #
+ # Reassociate the last addition into the first multiplication.
+ (('~fadd', ('ffma(is_used_once)', a, b, ('ffma', c, d, ('fmul', 'e(is_not_const_and_not_fsign)', 'f(is_not_const_and_not_fsign)'))), 'g(is_not_const)'),
+ ('ffma', a, b, ('ffma', c, d, ('ffma', e, 'f', 'g'))), '!options->intel_vec4'),
+ (('~fadd', ('ffma(is_used_once)', a, b, ('fmul', 'e(is_not_const_and_not_fsign)', 'f(is_not_const_and_not_fsign)') ), 'g(is_not_const)'),
+ ('ffma', a, b, ('ffma', e, 'f', 'g') ), '!options->intel_vec4'),
]
print(nir_algebraic.AlgebraicPass("nir_opt_algebraic", optimizations).render())
diff --git a/src/compiler/nir/nir_search_helpers.h b/src/compiler/nir/nir_search_helpers.h
index 658ed2b1d5b..7c19cd3fdfe 100644
--- a/src/compiler/nir/nir_search_helpers.h
+++ b/src/compiler/nir/nir_search_helpers.h
@@ -190,6 +190,30 @@ is_not_fmul(nir_alu_instr *instr, unsigned src,
}
static inline bool
+is_fsign(nir_alu_instr *instr, unsigned src,
+ UNUSED unsigned num_components, UNUSED const uint8_t *swizzle)
+{
+ nir_alu_instr *src_alu =
+ nir_src_as_alu_instr(instr->src[src].src);
+
+ if (src_alu == NULL)
+ return false;
+
+ if (src_alu->op == nir_op_fneg)
+ src_alu = nir_src_as_alu_instr(src_alu->src[0].src);
+
+ return src_alu->op == nir_op_fsign;
+}
+
+static inline bool
+is_not_const_and_not_fsign(nir_alu_instr *instr, unsigned src,
+ unsigned num_components, const uint8_t *swizzle)
+{
+ return is_not_const(instr, src, num_components, swizzle) &&
+ !is_fsign(instr, src, num_components, swizzle);
+}
+
+static inline bool
is_used_once(nir_alu_instr *instr)
{
bool zero_if_use = list_empty(&instr->dest.dest.ssa.if_uses);