summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/panfrost/midgard/compiler.h1
-rw-r--r--src/panfrost/midgard/midgard_compile.c1
-rw-r--r--src/panfrost/midgard/midgard_opt_invert.c122
3 files changed, 124 insertions, 0 deletions
diff --git a/src/panfrost/midgard/compiler.h b/src/panfrost/midgard/compiler.h
index cf9db9145a3..2aad68f14dd 100644
--- a/src/panfrost/midgard/compiler.h
+++ b/src/panfrost/midgard/compiler.h
@@ -577,6 +577,7 @@ void midgard_opt_post_move_eliminate(compiler_context *ctx, midgard_block *block
void midgard_lower_invert(compiler_context *ctx, midgard_block *block);
bool midgard_opt_not_propagate(compiler_context *ctx, midgard_block *block);
+bool midgard_opt_fuse_src_invert(compiler_context *ctx, midgard_block *block);
bool midgard_opt_fuse_dest_invert(compiler_context *ctx, midgard_block *block);
#endif
diff --git a/src/panfrost/midgard/midgard_compile.c b/src/panfrost/midgard/midgard_compile.c
index a3c66ca43bb..c4a50cbaee0 100644
--- a/src/panfrost/midgard/midgard_compile.c
+++ b/src/panfrost/midgard/midgard_compile.c
@@ -2358,6 +2358,7 @@ midgard_compile_shader_nir(struct midgard_screen *screen, nir_shader *nir, midga
progress |= midgard_opt_combine_projection(ctx, block);
progress |= midgard_opt_varying_projection(ctx, block);
progress |= midgard_opt_not_propagate(ctx, block);
+ progress |= midgard_opt_fuse_src_invert(ctx, block);
progress |= midgard_opt_fuse_dest_invert(ctx, block);
}
} while (progress);
diff --git a/src/panfrost/midgard/midgard_opt_invert.c b/src/panfrost/midgard/midgard_opt_invert.c
index ffe43a1b176..6a6be1d83ff 100644
--- a/src/panfrost/midgard/midgard_opt_invert.c
+++ b/src/panfrost/midgard/midgard_opt_invert.c
@@ -132,6 +132,32 @@ mir_invert_op(midgard_alu_op op)
}
}
+static midgard_alu_op
+mir_demorgan_op(midgard_alu_op op)
+{
+ switch (op) {
+ case midgard_alu_op_iand:
+ return midgard_alu_op_inor;
+ case midgard_alu_op_ior:
+ return midgard_alu_op_inand;
+ default:
+ unreachable("Op not De Morgan-able");
+ }
+}
+
+static midgard_alu_op
+mir_notright_op(midgard_alu_op op)
+{
+ switch (op) {
+ case midgard_alu_op_iand:
+ return midgard_alu_op_iandnot;
+ case midgard_alu_op_ior:
+ return midgard_alu_op_iornot;
+ default:
+ unreachable("Op not right able");
+ }
+}
+
bool
midgard_opt_fuse_dest_invert(compiler_context *ctx, midgard_block *block)
{
@@ -150,3 +176,99 @@ midgard_opt_fuse_dest_invert(compiler_context *ctx, midgard_block *block)
return progress;
}
+
+/* Next up, we can fuse inverts into the sources of bitwise ops:
+ *
+ * ~a & b = b & ~a = iandnot(b, a)
+ * a & ~b = iandnot(a, b)
+ * ~a & ~b = ~(a | b) = inor(a, b)
+ *
+ * ~a | b = b | ~a = iornot(b, a)
+ * a | ~b = iornot(a, b)
+ * ~a | ~b = ~(a & b) = inand(a, b)
+ *
+ * ~a ^ b = ~(a ^ b) = inxor(a, b)
+ * a ^ ~b = ~(a ^ b) + inxor(a, b)
+ * ~a ^ ~b = a ^ b
+ * ~(a ^ b) = inxor(a, b)
+ */
+
+static bool
+mir_strip_inverted(compiler_context *ctx, unsigned node)
+{
+ /* Strips and returns the invert off a node */
+ mir_foreach_instr_global(ctx, ins) {
+ if (ins->compact_branch) continue;
+ if (ins->ssa_args.dest != node) continue;
+
+ bool status = ins->invert;
+ ins->invert = false;
+ return status;
+ }
+
+ unreachable("Invalid node stripped");
+}
+
+bool
+midgard_opt_fuse_src_invert(compiler_context *ctx, midgard_block *block)
+{
+ bool progress = false;
+
+ mir_foreach_instr_in_block_safe(block, ins) {
+ /* Search for inverted bitwise */
+ if (ins->type != TAG_ALU_4) continue;
+ if (!mir_is_bitwise(ins)) continue;
+ if (ins->invert) continue;
+
+ if (ins->ssa_args.src0 & IS_REG) continue;
+ if (ins->ssa_args.src1 & IS_REG) continue;
+ if (!mir_single_use(ctx, ins->ssa_args.src0)) continue;
+ if (!ins->ssa_args.inline_constant && !mir_single_use(ctx, ins->ssa_args.src1)) continue;
+
+ bool not_a = mir_strip_inverted(ctx, ins->ssa_args.src0);
+ bool not_b =
+ ins->ssa_args.inline_constant ? false :
+ mir_strip_inverted(ctx, ins->ssa_args.src1);
+
+ /* Edge case: if src0 == src1, it'll've been stripped */
+ if ((ins->ssa_args.src0 == ins->ssa_args.src1) && !ins->ssa_args.inline_constant)
+ not_b = not_a;
+
+ progress |= (not_a || not_b);
+
+ /* No point */
+ if (!(not_a || not_b)) continue;
+
+ bool both = not_a && not_b;
+ bool left = not_a && !not_b;
+ bool right = !not_a && not_b;
+
+ /* No-op, but we got to strip the inverts */
+ if (both && ins->alu.op == midgard_alu_op_ixor)
+ continue;
+
+ if (both) {
+ ins->alu.op = mir_demorgan_op(ins->alu.op);
+ } else if (right || (left && !ins->ssa_args.inline_constant)) {
+ if (left) {
+ /* Commute */
+ unsigned temp = ins->ssa_args.src0;
+ ins->ssa_args.src0 = ins->ssa_args.src1;
+ ins->ssa_args.src1 = temp;
+ }
+
+ ins->alu.op = mir_notright_op(ins->alu.op);
+ } else if (left && ins->ssa_args.inline_constant) {
+ /* Some special transformations:
+ *
+ * ~A & c = ~(~(~A) | (~c)) = ~(A | ~c) = inor(A, ~c)
+ * ~A | c = ~(~(~A) & (~c)) = ~(A & ~c) = inand(A, ~c)
+ */
+
+ ins->alu.op = mir_demorgan_op(ins->alu.op);
+ ins->inline_constant = ~ins->inline_constant;
+ }
+ }
+
+ return progress;
+}