broadcom/compiler: remove unused leading ldunifa
authorIago Toral Quiroga <itoral@igalia.com>
Tue, 16 Feb 2021 11:08:05 +0000 (12:08 +0100)
committerMarge Bot <eric+marge@anholt.net>
Tue, 23 Feb 2021 08:08:01 +0000 (08:08 +0000)
This requires that we go back to the unifa write and update the address
to jump over the unused leading component.

Reviewed-by: Alejandro PiƱeiro <apinheiro@igalia.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/9128>

src/broadcom/compiler/vir_opt_dead_code.c

index d17f08a..59b458c 100644 (file)
@@ -91,7 +91,9 @@ vir_dce_flags(struct v3d_compile *c, struct qinst *inst)
 }
 
 static bool
-is_last_ldunifa(struct v3d_compile *c, struct qinst *inst, struct qblock *block)
+check_last_ldunifa(struct v3d_compile *c,
+                   struct qinst *inst,
+                   struct qblock *block)
 {
         if (!inst->qpu.sig.ldunifa && !inst->qpu.sig.ldunifarf)
                 return false;
@@ -116,6 +118,66 @@ is_last_ldunifa(struct v3d_compile *c, struct qinst *inst, struct qblock *block)
         return true;
 }
 
+static bool
+check_first_ldunifa(struct v3d_compile *c,
+                    struct qinst *inst,
+                    struct qblock *block,
+                    struct qinst **unifa)
+{
+        if (!inst->qpu.sig.ldunifa && !inst->qpu.sig.ldunifarf)
+                return false;
+
+        list_for_each_entry_from_rev(struct qinst, scan_inst, inst->link.prev,
+                                     &block->instructions, link) {
+                /* If we find a write to unifa, then this was the first
+                 * ldunifa in its sequence and is safe to remove.
+                 */
+                if (scan_inst->dst.file == QFILE_MAGIC &&
+                    scan_inst->dst.index == V3D_QPU_WADDR_UNIFA) {
+                        *unifa = scan_inst;
+                        return true;
+                }
+
+                /* If we find another ldunifa in the same sequence then we
+                 * can't remove it.
+                 */
+                if (scan_inst->qpu.sig.ldunifa || scan_inst->qpu.sig.ldunifarf)
+                        return false;
+        }
+
+        unreachable("could not find starting unifa for ldunifa sequence");
+}
+
+static bool
+increment_unifa_address(struct v3d_compile *c, struct qinst *unifa)
+{
+        if (unifa->qpu.type == V3D_QPU_INSTR_TYPE_ALU &&
+            unifa->qpu.alu.mul.op == V3D_QPU_M_MOV) {
+                c->cursor = vir_after_inst(unifa);
+                struct qreg unifa_reg = vir_reg(QFILE_MAGIC, V3D_QPU_WADDR_UNIFA);
+                vir_ADD_dest(c, unifa_reg, unifa->src[0], vir_uniform_ui(c, 4u));
+                vir_remove_instruction(c, unifa);
+                return true;
+        }
+
+        /* FIXME: we can optimize this further by implementing a constant
+         * ALU pass in the backend, for the case where we are skipping
+         * multiple leading ldunifa.
+         */
+        if (unifa->qpu.type == V3D_QPU_INSTR_TYPE_ALU &&
+            unifa->qpu.alu.add.op == V3D_QPU_A_ADD) {
+                c->cursor = vir_after_inst(unifa);
+                struct qreg unifa_reg = vir_reg(QFILE_MAGIC, V3D_QPU_WADDR_UNIFA);
+                struct qreg tmp =
+                        vir_ADD(c, unifa->src[1], vir_uniform_ui(c, 4u));
+                vir_ADD_dest(c, unifa_reg, unifa->src[0], tmp);
+                vir_remove_instruction(c, unifa);
+                return true;
+        }
+
+        return false;
+}
+
 bool
 vir_opt_dead_code(struct v3d_compile *c)
 {
@@ -151,8 +213,15 @@ vir_opt_dead_code(struct v3d_compile *c)
                                 continue;
                         }
 
+                        const bool is_last_ldunifa =
+                                check_last_ldunifa(c, inst, block);
+
+                        struct qinst *unifa = NULL;
+                        const bool is_first_ldunifa =
+                                check_first_ldunifa(c, inst, block, &unifa);
+
                         if (vir_has_side_effects(c, inst) &&
-                            !is_last_ldunifa(c, inst, block)) {
+                            !is_last_ldunifa && !is_first_ldunifa) {
                                 continue;
                         }
 
@@ -195,6 +264,15 @@ vir_opt_dead_code(struct v3d_compile *c)
                                 continue;
                         }
 
+                        /* If we are removing the first ldunifa in a sequence
+                         * we need to update the unifa address.
+                         */
+                        if (is_first_ldunifa) {
+                                assert(unifa);
+                                if (!increment_unifa_address(c, unifa))
+                                        continue;
+                        }
+
                         assert(inst != last_flags_write);
                         dce(c, inst);
                         progress = true;