[Mesa-dev] [PATCH v2 4/6] i965/vec4: Don't emit scratch reads for a register we have just unspilled

Iago Toral Quiroga itoral at igalia.com
Tue Jul 28 03:24:49 PDT 2015


Similar to reads inmmediately after spilling, there is no gain for register
allocation in unspilling the same vgrf in consecutive instructions, since
the gain only comes when there are gaps in the program that don't use the
vgrf. In these scenarios we can simply unspill once and reuse the result
for as long as consecutive instructions read it.
---
 .../drivers/dri/i965/brw_vec4_reg_allocate.cpp     | 37 ++++++++++++++++++++--
 1 file changed, 35 insertions(+), 2 deletions(-)

diff --git a/src/mesa/drivers/dri/i965/brw_vec4_reg_allocate.cpp b/src/mesa/drivers/dri/i965/brw_vec4_reg_allocate.cpp
index fd56dae..9a69fac 100644
--- a/src/mesa/drivers/dri/i965/brw_vec4_reg_allocate.cpp
+++ b/src/mesa/drivers/dri/i965/brw_vec4_reg_allocate.cpp
@@ -340,14 +340,16 @@ vec4_visitor::spill_reg(int spill_reg_nr)
    unsigned int spill_offset = last_scratch++;
 
    /* Generate spill/unspill instructions for the objects being spilled. */
+   int scratch_reg = -1;
+   unsigned unspill_swizzle_mask = 0;
    vec4_instruction *spill_write_inst = NULL;
+   vec4_instruction *spill_read_inst = NULL;
    foreach_block_and_inst(block, vec4_instruction, inst, cfg) {
       /* We don't spill registers used for scratch */
       if (inst->opcode == SHADER_OPCODE_GEN4_SCRATCH_READ ||
           inst->opcode == SHADER_OPCODE_GEN4_SCRATCH_WRITE)
          continue;
 
-      int scratch_reg = -1;
       bool spill_reg_was_read = false;
       for (unsigned int i = 0; i < 3; i++) {
          if (inst->src[i].file == GRF && inst->src[i].reg == spill_reg_nr) {
@@ -376,17 +378,48 @@ vec4_visitor::spill_reg(int spill_reg_nr)
                 ((brw_mask_for_swizzle(inst->src[i].swizzle) &
                  ~spill_write_inst->dst.writemask) == 0)) {
                scratch_reg = spill_write_inst->dst.reg;
-            } else if (scratch_reg == -1) {
+            }
+            /* Similarly, if we are reading the spilled register right after
+             * unspilling it, we do not need to unspill it again. For this to
+             * work we must check that:
+             *
+             * 1) The unspill was inconditional, that is, it was not predicated
+             *    or it was a SEL.
+             * 2) The channels we read are a subset of the channels we
+             *    unspilled
+             *
+             * We keep doing this for as long as the next instruction keeps
+             * reading the spilled register.
+             */
+            else if (scratch_reg == -1 ||
+                     !spill_read_inst ||
+                     (spill_read_inst->predicate &&
+                      spill_read_inst->opcode != BRW_OPCODE_SEL) ||
+                     ((brw_mask_for_swizzle(inst->src[i].swizzle) &
+                      ~unspill_swizzle_mask) != 0)) {
                scratch_reg = alloc.allocate(1);
                src_reg temp = inst->src[i];
                temp.reg = scratch_reg;
                emit_scratch_read(block, inst,
                                  dst_reg(temp), inst->src[i], spill_offset);
+               unspill_swizzle_mask =
+                  brw_mask_for_swizzle(inst->src[i].swizzle);
+               spill_read_inst = inst;
             }
+            assert(scratch_reg != -1);
             inst->src[i].reg = scratch_reg;
          }
       }
 
+      /* If this instruction did not read the spilled reg we will have to
+       * unspill it the next time we see it
+       */
+      if (!spill_reg_was_read) {
+         scratch_reg = -1;
+         unspill_swizzle_mask = 0;
+         spill_read_inst = NULL;
+      }
+
       if (inst->dst.file == GRF && inst->dst.reg == spill_reg_nr) {
          emit_scratch_write(block, inst, spill_offset);
          spill_write_inst = inst;
-- 
1.9.1



More information about the mesa-dev mailing list