<div dir="ltr"><div class="gmail_quote"><div dir="ltr">On Mon, Nov 12, 2018 at 8:57 PM Timothy Arceri <<a href="mailto:tarceri@itsqueeze.com">tarceri@itsqueeze.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">For example the following type of thing is seen in TCS from<br>
a number of Vulkan and DXVK games:<br>
<br>
        vec1 32 ssa_557 = deref_var &oPatch (shader_out float)<br>
        vec1 32 ssa_558 = intrinsic load_deref (ssa_557) ()<br>
        vec1 32 ssa_559 = deref_var &oPatch@42 (shader_out float)<br>
        vec1 32 ssa_560 = intrinsic load_deref (ssa_559) ()<br>
        vec1 32 ssa_561 = deref_var &oPatch@43 (shader_out float)<br>
        vec1 32 ssa_562 = intrinsic load_deref (ssa_561) ()<br>
        intrinsic store_deref (ssa_557, ssa_558) (1) /* wrmask=x */<br>
        intrinsic store_deref (ssa_559, ssa_560) (1) /* wrmask=x */<br>
        intrinsic store_deref (ssa_561, ssa_562) (1) /* wrmask=x */<br>
<br>
No shader-db changes on i965 (SKL).<br>
<br>
vkpipeline-db results RADV (VEGA):<br>
<br>
Totals from affected shaders:<br>
SGPRS: 7832 -> 7728 (-1.33 %)<br>
VGPRS: 6476 -> 6740 (4.08 %)<br>
Spilled SGPRs: 0 -> 0 (0.00 %)<br>
Spilled VGPRs: 0 -> 0 (0.00 %)<br>
Private memory VGPRs: 0 -> 0 (0.00 %)<br>
Scratch size: 0 -> 0 (0.00 %) dwords per thread<br>
Code Size: 469572 -> 456596 (-2.76 %) bytes<br>
LDS: 0 -> 0 (0.00 %) blocks<br>
Max Waves: 989 -> 960 (-2.93 %)<br>
Wait states: 0 -> 0 (0.00 %)<br>
<br>
The Max Waves and VGPRS changes here are misleading. What is<br>
happening is a bunch of TCS outputs are being optimised away as<br>
they are now recognised as unused. This results in more varyings<br>
being compacted via nir_compact_varyings() which can result in<br>
more register pressure when they are not packed in an optimal way.<br>
This is an existing problem independent of this patch. I've run<br>
some benchmarks and haven't noticed any performance regressions<br>
in affected games.<br>
<br>
V2: check all ssa values in case another store has altered the<br>
    value of a component.<br>
v3: only check components that are actually written<br>
---<br>
 src/compiler/nir/nir_opt_copy_prop_vars.c | 45 ++++++++++++++++++-----<br>
 1 file changed, 35 insertions(+), 10 deletions(-)<br>
<br>
diff --git a/src/compiler/nir/nir_opt_copy_prop_vars.c b/src/compiler/nir/nir_opt_copy_prop_vars.c<br>
index 7a21ad56c79..4631c1b0223 100644<br>
--- a/src/compiler/nir/nir_opt_copy_prop_vars.c<br>
+++ b/src/compiler/nir/nir_opt_copy_prop_vars.c<br>
@@ -86,6 +86,21 @@ struct copy_prop_var_state {<br>
    bool progress;<br>
 };<br>
<br>
+static bool<br>
+value_equals_ssa(struct value *value, nir_intrinsic_instr *intrin)<br></blockquote><div><br></div><div>Maybe call it value_equals_store_src and name the intrinsic input "store"?  That's a bit more descriptive.  With that,</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">
+{<br>
+   assert(intrin->intrinsic == nir_intrinsic_store_deref);<br>
+   uintptr_t write_mask = nir_intrinsic_write_mask(intrin);<br>
+<br>
+   for (unsigned i = 0; i < intrin->num_components; i++) {<br>
+      if ((write_mask & (1 << i)) &&<br>
+          value->ssa[i] != intrin->src[1].ssa)<br>
+         return false;<br>
+   }<br>
+<br>
+   return true;<br>
+}<br>
+<br>
 static struct vars_written *<br>
 create_vars_written(struct copy_prop_var_state *state)<br>
 {<br>
@@ -676,18 +691,28 @@ copy_prop_vars_block(struct copy_prop_var_state *state,<br>
       }<br>
<br>
       case nir_intrinsic_store_deref: {<br>
-         struct value value = {<br>
-            .is_ssa = true<br>
-         };<br>
-<br>
-         for (unsigned i = 0; i < intrin->num_components; i++)<br>
-            value.ssa[i] = intrin->src[1].ssa;<br>
-<br>
          nir_deref_instr *dst = nir_src_as_deref(intrin->src[0]);<br>
-         unsigned wrmask = nir_intrinsic_write_mask(intrin);<br>
          struct copy_entry *entry =<br>
-            get_entry_and_kill_aliases(copies, dst, wrmask);<br>
-         store_to_entry(state, entry, &value, wrmask);<br>
+            lookup_entry_for_deref(copies, dst, nir_derefs_equal_bit);<br>
+         if (entry && value_equals_ssa(&entry->src, intrin)) {<br>
+            /* If we are storing the value from a load of the same var the<br>
+             * store is redundant so remove it.<br>
+             */<br>
+            nir_instr_remove(instr);<br>
+         } else {<br>
+            struct value value = {<br>
+               .is_ssa = true<br>
+            };<br>
+<br>
+            for (unsigned i = 0; i < intrin->num_components; i++)<br>
+               value.ssa[i] = intrin->src[1].ssa;<br>
+<br>
+            unsigned wrmask = nir_intrinsic_write_mask(intrin);<br>
+            struct copy_entry *entry =<br>
+               get_entry_and_kill_aliases(copies, dst, wrmask);<br>
+            store_to_entry(state, entry, &value, wrmask);<br>
+         }<br>
+<br>
          break;<br>
       }<br>
<br>
-- <br>
2.19.1<br>
<br>
</blockquote></div></div>