<div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">On Thu, Sep 7, 2017 at 5:50 PM, Francisco Jerez <span dir="ltr"><<a href="mailto:currojerez@riseup.net" target="_blank">currojerez@riseup.net</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Currently the liveness analysis pass would extend a live interval up<br>
to the top of the program when no unconditional and complete<br>
definition of the variable is found that dominates all of its uses.<br>
<br>
This can lead to a serious performance problem in shaders containing<br>
many partial writes, like scalar arithmetic, FP64 and soon FP16<br>
operations.  The number of oversize live intervals in such workloads<br>
can cause the compilation time of the shader to explode because of the<br>
worse than quadratic behavior of the register allocator and scheduler<br>
when running out of registers, and it can also cause the running time<br>
of the shader to explode due to the amount of spilling it leads to,<br>
which is orders of magnitude slower than GRF memory.<br>
<br>
This patch fixes it by computing the intersection of our current live<br>
intervals with the subset of the program that can possibly be reached<br>
from any definition of the variable.  Extending the storage allocation<br>
of the variable beyond that is pretty useless because its value is<br>
guaranteed to be undefined at a point that cannot be reached from any<br>
definition.<br>
<br>
No significant change in the running time of shader-db (with 5%<br>
statistical significance).<br>
<br>
shader-db results on IVB:<br>
<br>
  total cycles in shared programs: 61108780 -> 60932856 (-0.29%)<br>
  cycles in affected programs: 16335482 -> 16159558 (-1.08%)<br>
  helped: 5121<br>
  HURT: 4347<br>
<br>
  total spills in shared programs: 1309 -> 1288 (-1.60%)<br>
  spills in affected programs: 249 -> 228 (-8.43%)<br>
  helped: 3<br>
  HURT: 0<br>
<br>
  total fills in shared programs: 1652 -> 1597 (-3.33%)<br>
  fills in affected programs: 262 -> 207 (-20.99%)<br>
  helped: 4<br>
  HURT: 0<br>
<br>
  LOST:   2<br>
  GAINED: 209<br>
<br>
shader-db results on BDW:<br>
<br>
  total cycles in shared programs: 67617262 -> 67361220 (-0.38%)<br>
  cycles in affected programs: 23397142 -> 23141100 (-1.09%)<br>
  helped: 8045<br>
  HURT: 6488<br>
<br>
  total spills in shared programs: 1456 -> 1252 (-14.01%)<br>
  spills in affected programs: 465 -> 261 (-43.87%)<br>
  helped: 3<br>
  HURT: 0<br>
<br>
  total fills in shared programs: 1720 -> 1465 (-14.83%)<br>
  fills in affected programs: 471 -> 216 (-54.14%)<br>
  helped: 4<br>
  HURT: 0<br>
<br>
  LOST:   2<br>
  GAINED: 162<br>
<br>
shader-db results on SKL:<br>
<br>
  total cycles in shared programs: 65436248 -> 65245186 (-0.29%)<br>
  cycles in affected programs: 22560936 -> 22369874 (-0.85%)<br>
  helped: 8457<br>
  HURT: 6247<br>
<br>
  total spills in shared programs: 437 -> 437 (0.00%)<br>
  spills in affected programs: 0 -> 0<br>
  helped: 0<br>
  HURT: 0<br>
<br>
  total fills in shared programs: 870 -> 854 (-1.84%)<br>
  fills in affected programs: 16 -> 0<br>
  helped: 1<br>
  HURT: 0<br>
<br>
  LOST:   0<br>
  GAINED: 107<br>
---<br>
 src/intel/compiler/brw_fs_<wbr>live_variables.cpp | 34 ++++++++++++++++++++++++----<br>
 src/intel/compiler/brw_fs_<wbr>live_variables.h   | 12 ++++++++++<br>
 2 files changed, 42 insertions(+), 4 deletions(-)<br>
<br>
diff --git a/src/intel/compiler/brw_fs_<wbr>live_variables.cpp b/src/intel/compiler/brw_fs_<wbr>live_variables.cpp<br>
index c449672a519..059f076fa51 100644<br>
--- a/src/intel/compiler/brw_fs_<wbr>live_variables.cpp<br>
+++ b/src/intel/compiler/brw_fs_<wbr>live_variables.cpp<br>
@@ -83,9 +83,11 @@ fs_live_variables::setup_one_<wbr>write(struct block_data *bd, fs_inst *inst,<br>
    /* The def[] bitset marks when an initialization in a block completely<br>
     * screens off previous updates of that variable (VGRF channel).<br>
     */<br>
-   if (inst->dst.file == VGRF && !inst->is_partial_write()) {<br>
-      if (!BITSET_TEST(bd->use, var))<br>
+   if (inst->dst.file == VGRF) {<br>
+      if (!inst->is_partial_write() && !BITSET_TEST(bd->use, var))<br>
          BITSET_SET(bd->def, var);<br>
+<br>
+      BITSET_SET(bd->defout, var);<br>
    }<br>
 }<br>
<br>
@@ -199,6 +201,28 @@ fs_live_variables::compute_<wbr>live_variables()<br>
          }<br>
       }<br>
    }<br>
+<br>
+   /* Propagate defin and defout down the CFG to calculate the union of live<br>
+    * variables potentially defined along any possible control flow path.<br>
+    */<br>
+   do {<br>
+      cont = false;<br>
+<br>
+      foreach_block (block, cfg) {<br>
+         const struct block_data *bd = &block_data[block->num];<br>
+<br>
+        foreach_list_typed(bblock_<wbr>link, child_link, link, &block->children) {<br>
+            struct block_data *child_bd = &block_data[child_link->block-<wbr>>num];<br>
+<br>
+           for (int i = 0; i < bitset_words; i++) {<br>
+               const BITSET_WORD new_def = bd->defout[i] & ~child_bd->defin[i];<br></blockquote><div><br></div><div>Mind adding a comment here:</div><div><br></div><div>/* defin is a subset of defout so if we make progress on defout we must make progress on defin as well. */</div><div><br></div><div>Other than that, looks good to me.  I don't think this adds all that muc complication.</div><div><br></div><div>Reviewed-by: Jason Ekstrand <<a href="mailto:jason@jlekstrand.net">jason@jlekstrand.net</a>><br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+               child_bd->defin[i] |= new_def;<br>
+               child_bd->defout[i] |= new_def;<br>
+               cont |= new_def;<br>
+           }<br>
+        }<br>
+      }<br>
+   } while (cont);<br>
 }<br>
<br>
 /**<br>
@@ -212,12 +236,12 @@ fs_live_variables::compute_<wbr>start_end()<br>
       struct block_data *bd = &block_data[block->num];<br>
<br>
       for (int i = 0; i < num_vars; i++) {<br>
-         if (BITSET_TEST(bd->livein, i)) {<br>
+         if (BITSET_TEST(bd->livein, i) && BITSET_TEST(bd->defin, i)) {<br>
             start[i] = MIN2(start[i], block->start_ip);<br>
             end[i] = MAX2(end[i], block->start_ip);<br>
          }<br>
<br>
-         if (BITSET_TEST(bd->liveout, i)) {<br>
+         if (BITSET_TEST(bd->liveout, i) && BITSET_TEST(bd->defout, i)) {<br>
             start[i] = MIN2(start[i], block->end_ip);<br>
             end[i] = MAX2(end[i], block->end_ip);<br>
          }<br>
@@ -260,6 +284,8 @@ fs_live_variables::fs_live_<wbr>variables(fs_visitor *v, const cfg_t *cfg)<br>
       block_data[i].use = rzalloc_array(mem_ctx, BITSET_WORD, bitset_words);<br>
       block_data[i].livein = rzalloc_array(mem_ctx, BITSET_WORD, bitset_words);<br>
       block_data[i].liveout = rzalloc_array(mem_ctx, BITSET_WORD, bitset_words);<br>
+      block_data[i].defin = rzalloc_array(mem_ctx, BITSET_WORD, bitset_words);<br>
+      block_data[i].defout = rzalloc_array(mem_ctx, BITSET_WORD, bitset_words);<br>
<br>
       block_data[i].flag_def[0] = 0;<br>
       block_data[i].flag_use[0] = 0;<br>
diff --git a/src/intel/compiler/brw_fs_<wbr>live_variables.h b/src/intel/compiler/brw_fs_<wbr>live_variables.h<br>
index d2d5898ed1c..9e95e443170 100644<br>
--- a/src/intel/compiler/brw_fs_<wbr>live_variables.h<br>
+++ b/src/intel/compiler/brw_fs_<wbr>live_variables.h<br>
@@ -55,6 +55,18 @@ struct block_data {<br>
    /** Which defs reach the exit point of the block. */<br>
    BITSET_WORD *liveout;<br>
<br>
+   /**<br>
+    * Variables such that the entry point of the block may be reached from any<br>
+    * of their definitions.<br>
+    */<br>
+   BITSET_WORD *defin;<br>
+<br>
+   /**<br>
+    * Variables such that the exit point of the block may be reached from any<br>
+    * of their definitions.<br>
+    */<br>
+   BITSET_WORD *defout;<br>
+<br>
    BITSET_WORD flag_def[1];<br>
    BITSET_WORD flag_use[1];<br>
    BITSET_WORD flag_livein[1];<br>
<span class="HOEnZb"><font color="#888888">--<br>
2.14.1<br>
<br>
</font></span></blockquote></div><br></div></div>