[Mesa-dev] [PATCH 06/10] i965/vs: Add support for compute-to-MRF.

Eric Anholt eric at anholt.net
Thu Sep 8 23:32:23 PDT 2011


Removes 1.8% of the instructions from 97% of the vertex shaders in
shader-db.
---
 src/mesa/drivers/dri/i965/brw_vec4.cpp      |  177 +++++++++++++++++++++++++++
 src/mesa/drivers/dri/i965/brw_vec4.h        |    1 +
 src/mesa/drivers/dri/i965/brw_vec4_emit.cpp |    1 +
 3 files changed, 179 insertions(+), 0 deletions(-)

diff --git a/src/mesa/drivers/dri/i965/brw_vec4.cpp b/src/mesa/drivers/dri/i965/brw_vec4.cpp
index 2a8d63a..4a191af 100644
--- a/src/mesa/drivers/dri/i965/brw_vec4.cpp
+++ b/src/mesa/drivers/dri/i965/brw_vec4.cpp
@@ -519,4 +519,181 @@ vec4_visitor::move_push_constants_to_pull_constants()
    pack_uniform_registers();
 }
 
+/*
+ * Tries to reduce extra MOV instructions by taking GRFs that get just
+ * written and then MOVed into an MRF and making the original write of
+ * the GRF write directly to the MRF instead.
+ */
+bool
+vec4_visitor::opt_compute_to_mrf()
+{
+   bool progress = false;
+   int next_ip = 0;
+
+   calculate_live_intervals();
+
+   foreach_list_safe(node, &this->instructions) {
+      vec4_instruction *inst = (vec4_instruction *)node;
+
+      int ip = next_ip;
+      next_ip++;
+
+      if (inst->opcode != BRW_OPCODE_MOV ||
+	  inst->predicate ||
+	  inst->dst.file != MRF || inst->src[0].file != GRF ||
+	  inst->dst.type != inst->src[0].type ||
+	  inst->src[0].abs || inst->src[0].negate || inst->src[0].reladdr)
+	 continue;
+
+      int mrf = inst->dst.reg;
+
+      /* Can't compute-to-MRF this GRF if someone else was going to
+       * read it later.
+       */
+      if (this->virtual_grf_use[inst->src[0].reg] > ip)
+	 continue;
+
+      /* We need to check interference with the MRF between this
+       * instruction and the earliest instruction involved in writing
+       * the GRF we're eliminating.  To do that, keep track of which
+       * of our source channels we've seen initialized.
+       */
+      bool chans_needed[4] = {false, false, false, false};
+      int chans_remaining = 0;
+      for (int i = 0; i < 4; i++) {
+	 int chan = BRW_GET_SWZ(inst->src[0].swizzle, i);
+
+	 if (!(inst->dst.writemask & (1 << i)))
+	    continue;
+
+	 /* We don't handle compute-to-MRF across a swizzle.  We would
+	  * need to be able to rewrite instructions above to output
+	  * results to different channels.
+	  */
+	 if (chan != i)
+	    chans_remaining = 5;
+
+	 if (!chans_needed[chan]) {
+	    chans_needed[chan] = true;
+	    chans_remaining++;
+	 }
+      }
+      if (chans_remaining > 4)
+	 continue;
+
+      /* Now walk up the instruction stream trying to see if we can
+       * rewrite everything writing to the GRF into the MRF instead.
+       */
+      vec4_instruction *scan_inst;
+      for (scan_inst = (vec4_instruction *)inst->prev;
+	   scan_inst->prev != NULL;
+	   scan_inst = (vec4_instruction *)scan_inst->prev) {
+	 if (scan_inst->dst.file == GRF &&
+	     scan_inst->dst.reg == inst->src[0].reg &&
+	     scan_inst->dst.reg_offset == inst->src[0].reg_offset) {
+	    /* Found something writing to the reg we want to turn into
+	     * a compute-to-MRF.
+	     */
+
+	    /* SEND instructions can't have MRF as a destination. */
+	    if (scan_inst->mlen)
+	       break;
+
+	    if (intel->gen >= 6) {
+	       /* gen6 math instructions must have the destination be
+		* GRF, so no compute-to-MRF for them.
+		*/
+	       if (scan_inst->is_math()) {
+		  break;
+	       }
+	    }
+
+	    /* Mark which channels we found unconditional writes for. */
+	    if (!scan_inst->predicate) {
+	       for (int i = 0; i < 4; i++) {
+		  if (scan_inst->dst.writemask & (1 << i) &&
+		      chans_needed[i]) {
+		     chans_needed[i] = false;
+		     chans_remaining--;
+		  }
+	       }
+	    }
+
+	    if (chans_remaining == 0)
+	       break;
+	 }
+
+	 /* We don't handle flow control here.  Most computation of
+	  * values that end up in MRFs are shortly before the MRF
+	  * write anyway.
+	  */
+	 if (scan_inst->opcode == BRW_OPCODE_DO ||
+	     scan_inst->opcode == BRW_OPCODE_WHILE ||
+	     scan_inst->opcode == BRW_OPCODE_ELSE ||
+	     scan_inst->opcode == BRW_OPCODE_ENDIF) {
+	    break;
+	 }
+
+	 /* You can't read from an MRF, so if someone else reads our
+	  * MRF's source GRF that we wanted to rewrite, that stops us.
+	  */
+	 bool interfered = false;
+	 for (int i = 0; i < 3; i++) {
+	    if (scan_inst->src[i].file == GRF &&
+		scan_inst->src[i].reg == inst->src[0].reg &&
+		scan_inst->src[i].reg_offset == inst->src[0].reg_offset) {
+	       interfered = true;
+	    }
+	 }
+	 if (interfered)
+	    break;
+
+	 /* If somebody else writes our MRF here, we can't
+	  * compute-to-MRF before that.
+	  */
+	 if (scan_inst->dst.file == MRF && mrf == scan_inst->dst.reg)
+	    break;
+
+	 if (scan_inst->mlen > 0) {
+	    /* Found a SEND instruction, which means that there are
+	     * live values in MRFs from base_mrf to base_mrf +
+	     * scan_inst->mlen - 1.  Don't go pushing our MRF write up
+	     * above it.
+	     */
+	    if (mrf >= scan_inst->base_mrf &&
+		mrf < scan_inst->base_mrf + scan_inst->mlen) {
+	       break;
+	    }
+	 }
+      }
+
+      if (chans_remaining == 0) {
+	 /* If we've made it here, we have an inst we want to
+	  * compute-to-MRF, and a scan_inst pointing to the earliest
+	  * instruction involved in computing the value.  Now go
+	  * rewrite the instruction stream between the two.
+	  */
+
+	 while (scan_inst != inst) {
+	    if (scan_inst->dst.file == GRF &&
+		scan_inst->dst.reg == inst->src[0].reg &&
+		scan_inst->dst.reg_offset == inst->src[0].reg_offset) {
+	       scan_inst->dst.file = MRF;
+	       scan_inst->dst.reg = mrf;
+	       scan_inst->dst.reg_offset = 0;
+	       scan_inst->saturate |= inst->saturate;
+	    }
+	    scan_inst = (vec4_instruction *)scan_inst->next;
+	 }
+	 inst->remove();
+	 progress = true;
+      }
+   }
+
+   if (progress)
+      live_intervals_valid = false;
+
+   return progress;
+}
+
 } /* namespace brw */
diff --git a/src/mesa/drivers/dri/i965/brw_vec4.h b/src/mesa/drivers/dri/i965/brw_vec4.h
index e305e6f..90c1cbc 100644
--- a/src/mesa/drivers/dri/i965/brw_vec4.h
+++ b/src/mesa/drivers/dri/i965/brw_vec4.h
@@ -400,6 +400,7 @@ public:
    bool virtual_grf_interferes(int a, int b);
    bool opt_copy_propagation();
    bool opt_algebraic();
+   bool opt_compute_to_mrf();
 
    vec4_instruction *emit(vec4_instruction *inst);
 
diff --git a/src/mesa/drivers/dri/i965/brw_vec4_emit.cpp b/src/mesa/drivers/dri/i965/brw_vec4_emit.cpp
index 15f2458..ecaf8b4 100644
--- a/src/mesa/drivers/dri/i965/brw_vec4_emit.cpp
+++ b/src/mesa/drivers/dri/i965/brw_vec4_emit.cpp
@@ -622,6 +622,7 @@ vec4_visitor::run()
       progress = dead_code_eliminate() || progress;
       progress = opt_copy_propagation() || progress;
       progress = opt_algebraic() || progress;
+      progress = opt_compute_to_mrf() || progress;
    } while (progress);
 
 
-- 
1.7.5.4



More information about the mesa-dev mailing list