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

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


When we have code such as this:

mov vgrf1.0.x:F, vgrf2.xxxx:F
mov vgrf3.0.x:F, vgrf1.xxxx:F
...
mov vgrf3.0.x:F, vgrf1.xxxx:F

And vgrf1 is chosen for spilling, we can emit this:

mov vgrf1.0.x:F, vgrf2.xxxx:F
gen4_scratch_write hw_reg0:F, vgrf1.xxxx:D, 22D
mov vgrf3.0.x:F, vgrf1.xxxx:F
...
gen4_scratch_read vgrf4.0.x:F, 22D
mov vgrf3.0.x:F, vgrf4.xxxx:F

Instead of this:

mov vgrf1.0.x:F, vgrf2.xxxx:F
gen4_scratch_write hw_reg0:F, vgrf1.xxxx:D, 22D
gen4_scratch_read vgrf4.0.x:F, 22D
mov vgrf3.0.x:F, vgrf4.xxxx:F
...
gen4_scratch_read vgrf5.0.x:F, 22D
mov vgrf3.0.x:F, vgrf5.xxxx:F

And save one scratch read while still preserving the benefits of
spilling the register.

In general, we avoid emitting scratch reads for as long as the next instruction
keeps reading the spilled register. This should not harm the benefit of
spilling the register because gains for register allocation only come when we
have chunks of program code where the register is alive but not really used
(because these are the points where we could effectively use that register for
another purpose if we spilled it), so as long as consecutive instructions use
that register we can avoid the scratch reads without losing anything.
---
 .../drivers/dri/i965/brw_vec4_reg_allocate.cpp     | 37 +++++++++++++++++++++-
 1 file changed, 36 insertions(+), 1 deletion(-)

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 cff5406..fd56dae 100644
--- a/src/mesa/drivers/dri/i965/brw_vec4_reg_allocate.cpp
+++ b/src/mesa/drivers/dri/i965/brw_vec4_reg_allocate.cpp
@@ -340,11 +340,43 @@ vec4_visitor::spill_reg(int spill_reg_nr)
    unsigned int spill_offset = last_scratch++;
 
    /* Generate spill/unspill instructions for the objects being spilled. */
+   vec4_instruction *spill_write_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) {
-            if (scratch_reg == -1) {
+            if (!spill_reg_was_read) {
+               spill_reg_was_read = (!inst->predicate ||
+                                     inst->opcode == BRW_OPCODE_SEL);
+            }
+
+            /* If we are reading the spilled register right after writing
+             * to it we can skip the scratch read and use directly the
+             * register we used as source for the scratch write. For this
+             * to work we must check that:
+             *
+             * 1) The write is inconditional, that is, it is not predicated or
+             *    it is a SEL.
+             * 2) All the channels that we read have been written in that
+             *    last write instruction.
+             *
+             * We keep doing this for as long as the next instruction
+             * keeps reading the spilled register and break as soon as we
+             * find an instruction that doesn't.
+             */
+            if (spill_write_inst &&
+                (!spill_write_inst->predicate ||
+                 spill_write_inst->opcode == BRW_OPCODE_SEL) &&
+                ((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) {
                scratch_reg = alloc.allocate(1);
                src_reg temp = inst->src[i];
                temp.reg = scratch_reg;
@@ -357,6 +389,9 @@ vec4_visitor::spill_reg(int spill_reg_nr)
 
       if (inst->dst.file == GRF && inst->dst.reg == spill_reg_nr) {
          emit_scratch_write(block, inst, spill_offset);
+         spill_write_inst = inst;
+      } else if (spill_write_inst && !spill_reg_was_read) {
+         spill_write_inst = NULL;
       }
    }
 
-- 
1.9.1



More information about the mesa-dev mailing list