pan/midgard: Implement SIMD-aware dead code elimination
[mesa.git] / src / panfrost / midgard / midgard_opt_dce.c
index 613eb6e5b1d61ad18d29576d3c5b00d177c9e573..aaac84fe16e4608a0b9681d953f6d4b36b278198 100644 (file)
  */
 
 #include "compiler.h"
+#include "util/u_memory.h"
+#include "midgard_ops.h"
 
-/* Basic dead code elimination on the MIR itself */
+/* SIMD-aware dead code elimination. Perform liveness analysis step-by-step,
+ * removing dead components. If an instruction ends up with a zero mask, the
+ * instruction in total is dead and should be removed. */
+
+static bool
+can_cull_mask(compiler_context *ctx, midgard_instruction *ins)
+{
+        if (ins->dest >= ctx->temp_count)
+                return false;
+
+        if (ins->type == TAG_LOAD_STORE_4)
+                if (load_store_opcode_props[ins->load_store.op].props & LDST_SPECIAL_MASK)
+                        return false;
+
+        return true;
+}
+
+static bool
+can_dce(midgard_instruction *ins)
+{
+        if (ins->mask)
+                return false;
+
+        if (ins->compact_branch)
+                return false;
+
+        if (ins->type == TAG_LOAD_STORE_4)
+                if (load_store_opcode_props[ins->load_store.op].props & LDST_SIDE_FX)
+                        return false;
+
+        return true;
+}
 
 bool
 midgard_opt_dead_code_eliminate(compiler_context *ctx, midgard_block *block)
@@ -32,18 +65,34 @@ midgard_opt_dead_code_eliminate(compiler_context *ctx, midgard_block *block)
         bool progress = false;
 
         mir_invalidate_liveness(ctx);
+        mir_compute_liveness(ctx);
 
-        mir_foreach_instr_in_block_safe(block, ins) {
-                if (ins->type != TAG_ALU_4) continue;
-                if (ins->compact_branch) continue;
+        uint16_t *live = mem_dup(block->live_out, ctx->temp_count * sizeof(uint16_t));
+
+        mir_foreach_instr_in_block_rev(block, ins) {
+                if (can_cull_mask(ctx, ins)) {
+                        midgard_reg_mode mode = mir_typesize(ins);
+                        unsigned oldmask = ins->mask;
+
+                        unsigned rounded = mir_round_bytemask_down(live[ins->dest], mode);
+                        unsigned cmask = mir_from_bytemask(rounded, mode);
+
+                        ins->mask &= cmask;
+                        progress |= (ins->mask != oldmask);
+                }
 
-                if (ins->dest >= SSA_FIXED_MINIMUM) continue;
-                if (mir_is_live_after(ctx, block, ins, ins->dest)) continue;
+                mir_liveness_ins_update(live, ins, ctx->temp_count);
+        }
 
-                mir_remove_instruction(ins);
-                progress = true;
+        mir_foreach_instr_in_block_safe(block, ins) {
+                if (can_dce(ins)) {
+                        mir_remove_instruction(ins);
+                        progress = true;
+                }
         }
 
+        free(live);
+
         return progress;
 }