pan/mdg: Optimize pipelining logic
authorAlyssa Rosenzweig <alyssa.rosenzweig@collabora.com>
Wed, 6 May 2020 19:36:38 +0000 (15:36 -0400)
committerMarge Bot <eric+marge@anholt.net>
Wed, 20 May 2020 17:06:34 +0000 (17:06 +0000)
The test and rewrite were both accidentally O(N) to the shader size when
they should be O(1), so overall this takes the pass from O(N^2) to O(N).

Signed-off-by: Alyssa Rosenzweig <alyssa.rosenzweig@collabora.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/5123>

src/panfrost/midgard/compiler.h
src/panfrost/midgard/midgard_ra_pipeline.c
src/panfrost/midgard/mir.c

index 67d56035a8bd1f30382b06ad60efaf206c7151f3..618c0d792655f05ff6ae5c89986416a1e1cf8db6 100644 (file)
@@ -483,7 +483,6 @@ void mir_rewrite_index_src_swizzle(compiler_context *ctx, unsigned old, unsigned
 bool mir_single_use(compiler_context *ctx, unsigned value);
 bool mir_special_index(compiler_context *ctx, unsigned idx);
 unsigned mir_use_count(compiler_context *ctx, unsigned value);
-bool mir_is_written_before(compiler_context *ctx, midgard_instruction *ins, unsigned node);
 uint16_t mir_bytemask_of_read_components(midgard_instruction *ins, unsigned node);
 uint16_t mir_bytemask_of_read_components_index(midgard_instruction *ins, unsigned i);
 midgard_reg_mode mir_typesize(midgard_instruction *ins);
index 48f45cb9adb98145f2b501e081359d831ef82a6d..1037d0645d95eaf18fa0407b26468ca56bc709ac 100644 (file)
@@ -47,18 +47,30 @@ mir_pipeline_ins(
 {
         midgard_instruction *ins = bundle->instructions[i];
 
-        /* We could be pipelining a register, so we need to make sure that all
-         * of the components read in this bundle are written in this bundle,
-         * and that no components are written before this bundle */
+        /* Our goal is to create a pipeline register. Pipeline registers are
+         * created at the start of the bundle and are destroyed at the end. So
+         * we conservatively require:
+         *
+         *  1. Each component read in the second stage is written in the first stage.
+         *  2. The index is not live after the bundle.
+         *  3. We're not a special index (writeout, conditionals, ..)
+         *
+         * Rationale: #1 ensures that there is no need to go before the
+         * creation of the bundle, so the pipeline register can exist. #2 is
+         * since the pipeline register will be destroyed at the end. This
+         * ensures that nothing will try to read/write the pipeline register
+         * once it is not live, and that there's no need to go earlier. */
 
         unsigned node = ins->dest;
         unsigned read_mask = 0;
 
+        if (node >= SSA_FIXED_MINIMUM)
+                return false;
+
         /* Analyze the bundle for a per-byte read mask */
 
         for (unsigned j = 0; j < bundle->instruction_count; ++j) {
                 midgard_instruction *q = bundle->instructions[j];
-                read_mask |= mir_bytemask_of_read_components(q, node);
 
                 /* The fragment colour can't be pipelined (well, it is
                  * pipelined in r0, but this is a delicate dance with
@@ -66,11 +78,15 @@ mir_pipeline_ins(
 
                 if (q->compact_branch && q->writeout && mir_has_arg(q, node))
                         return false;
+
+                if (q->unit < UNIT_VADD) continue;
+                read_mask |= mir_bytemask_of_read_components(q, node);
         }
 
-        /* Now analyze for a write mask */
+        /* Now check what's written in the beginning stage  */
         for (unsigned j = 0; j < bundle->instruction_count; ++j) {
                 midgard_instruction *q = bundle->instructions[j];
+                if (q->unit >= UNIT_VADD) break;
                 if (q->dest != node) continue;
 
                 /* Remove the written mask from the read requirements */
@@ -81,12 +97,6 @@ mir_pipeline_ins(
         if (read_mask)
                 return false;
 
-        /* Now, check outside the bundle */
-        midgard_instruction *start = bundle->instructions[0];
-
-        if (mir_is_written_before(ctx, start, node))
-                return false;
-
         /* We want to know if we live after this bundle, so check if
          * we're live after the last instruction of the bundle */
 
@@ -97,8 +107,16 @@ mir_pipeline_ins(
                 return false;
 
         /* We're only live in this bundle -- pipeline! */
+        unsigned preg = SSA_FIXED_REGISTER(24 + pipeline_count);
+
+        for (unsigned j = 0; j < bundle->instruction_count; ++j) {
+                midgard_instruction *q = bundle->instructions[j];
 
-        mir_rewrite_index(ctx, node, SSA_FIXED_REGISTER(24 + pipeline_count));
+                if (q->unit >= UNIT_VADD)
+                        mir_rewrite_index_src_single(q, node, preg);
+                else
+                        mir_rewrite_index_dst_single(q, node, preg);
+        }
 
         return true;
 }
index 7dc357e62ac6291ed1a17fbba5852ab3de174939..68f6286c590efc3a9b4847fb1d97143291b29eef 100644 (file)
@@ -197,25 +197,6 @@ mir_special_index(compiler_context *ctx, unsigned idx)
         return false;
 }
 
-/* Is a node written before a given instruction? */
-
-bool
-mir_is_written_before(compiler_context *ctx, midgard_instruction *ins, unsigned node)
-{
-        if (node >= SSA_FIXED_MINIMUM)
-                return true;
-
-        mir_foreach_instr_global(ctx, q) {
-                if (q == ins)
-                        break;
-
-                if (q->dest == node)
-                        return true;
-        }
-
-        return false;
-}
-
 /* Grabs the type size. */
 
 midgard_reg_mode