[Mesa-dev] [PATCH V6 05/27] glsl: remove dead code in a single pass

Ian Romanick idr at freedesktop.org
Tue Oct 6 12:48:53 PDT 2015


On 09/28/2015 07:42 PM, Timothy Arceri wrote:
> Currently only one ir assignment is removed for each var in a single
> dead code optimisation pass. This means if a var has more than one
> assignment, then it requires all the glsl optimisations to be run again
> for each additional assignment to be removed.
> Another pass is also required to remove the variable itself.
> 
> With this change all assignments and the variable are removed in a single
> pass.
> 
> Some of the arrays of arrays conformance tests that were looping
> through 8 dimensions ended up with a var with hundreds of assignments.
> 
> This change helps ES31-CTS.arrays_of_arrays.InteractionFunctionCalls1
> go from around 3 min 20 sec -> 2 min
> 
> ES31-CTS.arrays_of_arrays.InteractionFunctionCalls2 went from
> around 9 min 20 sec to 7 min 30 sec
> 
> I had difficulty getting the public shader-db to give a consistent result
> with or without this change but the results seemed unchanged at between
> 15-20 seconds.
> 
> Thomas Helland measured change with shader-db on his machine from
> approx 117 secs to 112 secs.
> 
> V3: Simplify freeing of list as suggested by Ian, and spelling fixes.
> 
> V2: Add assert to be sure references are counted before assignments.
> 
> Tested-By: Thomas Helland <thomashelland90 at gmail.com>
> ---
>  src/glsl/ir_variable_refcount.cpp | 27 ++++++++++++++++++++++++---
>  src/glsl/ir_variable_refcount.h   | 13 ++++++++++++-
>  src/glsl/opt_dead_code.cpp        | 33 ++++++++++++++++++++++-----------
>  src/glsl/opt_tree_grafting.cpp    |  2 --
>  4 files changed, 58 insertions(+), 17 deletions(-)
> 
> diff --git a/src/glsl/ir_variable_refcount.cpp b/src/glsl/ir_variable_refcount.cpp
> index e4d825c..c8a5575 100644
> --- a/src/glsl/ir_variable_refcount.cpp
> +++ b/src/glsl/ir_variable_refcount.cpp
> @@ -46,6 +46,15 @@ static void
>  free_entry(struct hash_entry *entry)
>  {
>     ir_variable_refcount_entry *ivre = (ir_variable_refcount_entry *) entry->data;
> +
> +   /* Free assignment list */
> +   exec_node *n;
> +   while ((n = ivre->assign_list.pop_head()) != NULL) {
> +      struct assignment_entry *assignment_entry =
> +         exec_node_data(struct assignment_entry, n, link);
> +      free(assignment_entry);
> +   }
> +
>     delete ivre;
>  }
>  
> @@ -59,7 +68,6 @@ ir_variable_refcount_visitor::~ir_variable_refcount_visitor()
>  ir_variable_refcount_entry::ir_variable_refcount_entry(ir_variable *var)
>  {
>     this->var = var;
> -   assign = NULL;
>     assigned_count = 0;
>     declaration = false;
>     referenced_count = 0;
> @@ -125,8 +133,21 @@ ir_variable_refcount_visitor::visit_leave(ir_assignment *ir)
>     entry = this->get_variable_entry(ir->lhs->variable_referenced());
>     if (entry) {
>        entry->assigned_count++;
> -      if (entry->assign == NULL)
> -	 entry->assign = ir;
> +
> +      /**

This is not a doxygen comment. :)  With that fixed, this patch is

Reviewed-by: Ian Romanick <ian.d.romanick at intel.com>

I also ran it through our CI system, so

Tested-by: Ian Romanick <ian.d.romanick at intel.com>

> +       * Build a list for dead code optimisation. Don't add assignment if it
> +       * was declared out of scope (outside the instruction stream). Also don't
> +       * bother adding any more to the list if there are more references than
> +       * assignments as this means the variable is used and won't be optimised
> +       * out.
> +       */
> +      assert(entry->referenced_count >= entry->assigned_count);
> +      if (entry->referenced_count == entry->assigned_count) {
> +         struct assignment_entry *assignment_entry =
> +            (struct assignment_entry *)calloc(1, sizeof(*assignment_entry));
> +         assignment_entry->assign = ir;
> +         entry->assign_list.push_head(&assignment_entry->link);
> +      }
>     }
>  
>     return visit_continue;
> diff --git a/src/glsl/ir_variable_refcount.h b/src/glsl/ir_variable_refcount.h
> index c15e8110..5c74c31 100644
> --- a/src/glsl/ir_variable_refcount.h
> +++ b/src/glsl/ir_variable_refcount.h
> @@ -33,13 +33,24 @@
>  #include "ir_visitor.h"
>  #include "glsl_types.h"
>  
> +struct assignment_entry {
> +   exec_node link;
> +   ir_assignment *assign;
> +};
> +
>  class ir_variable_refcount_entry
>  {
>  public:
>     ir_variable_refcount_entry(ir_variable *var);
>  
>     ir_variable *var; /* The key: the variable's pointer. */
> -   ir_assignment *assign; /* An assignment to the variable, if any */
> +
> +   /**
> +    * List of assignments to the variable, if any.
> +    * This is intended to be used for dead code optimisation and may
> +    * not be a complete list.
> +    */
> +   exec_list assign_list;
>  
>     /** Number of times the variable is referenced, including assignments. */
>     unsigned referenced_count;
> diff --git a/src/glsl/opt_dead_code.cpp b/src/glsl/opt_dead_code.cpp
> index 2cb7f41..4fa259c 100644
> --- a/src/glsl/opt_dead_code.cpp
> +++ b/src/glsl/opt_dead_code.cpp
> @@ -75,24 +75,35 @@ do_dead_code(exec_list *instructions, bool uniform_locations_assigned)
>  	  || !entry->declaration)
>  	 continue;
>  
> -      if (entry->assign) {
> -	 /* Remove a single dead assignment to the variable we found.
> -	  * Don't do so if it's a shader or function output or a shader
> -	  * storage variable though.
> +      if (!entry->assign_list.is_empty()) {
> +	 /* Remove all the dead assignments to the variable we found.
> +	  * Don't do so if it's a shader or function output, though.
>  	  */
>  	 if (entry->var->data.mode != ir_var_function_out &&
>  	     entry->var->data.mode != ir_var_function_inout &&
>               entry->var->data.mode != ir_var_shader_out &&
>               entry->var->data.mode != ir_var_shader_storage) {
> -	    entry->assign->remove();
> -	    progress = true;
>  
> -	    if (debug) {
> -	       printf("Removed assignment to %s@%p\n",
> -		      entry->var->name, (void *) entry->var);
> -	    }
> +            while (!entry->assign_list.is_empty()) {
> +               struct assignment_entry *assignment_entry =
> +                  exec_node_data(struct assignment_entry,
> +                                 entry->assign_list.head, link);
> +
> +	       assignment_entry->assign->remove();
> +
> +	       if (debug) {
> +	          printf("Removed assignment to %s@%p\n",
> +		         entry->var->name, (void *) entry->var);
> +               }
> +
> +               assignment_entry->link.remove();
> +               free(assignment_entry);
> +            }
> +            progress = true;
>  	 }
> -      } else {
> +      }
> +
> +      if (entry->assign_list.is_empty()) {
>  	 /* If there are no assignments or references to the variable left,
>  	  * then we can remove its declaration.
>  	  */
> diff --git a/src/glsl/opt_tree_grafting.cpp b/src/glsl/opt_tree_grafting.cpp
> index a7a219c..e38a0e9 100644
> --- a/src/glsl/opt_tree_grafting.cpp
> +++ b/src/glsl/opt_tree_grafting.cpp
> @@ -373,8 +373,6 @@ tree_grafting_basic_block(ir_instruction *bb_first,
>  	  entry->referenced_count != 2)
>  	 continue;
>  
> -      assert(assign == entry->assign);
> -
>        /* Found a possibly graftable assignment.  Now, walk through the
>         * rest of the BB seeing if the deref is here, and if nothing interfered with
>         * pasting its expression's values in between.
> 



More information about the mesa-dev mailing list