Home | History | Annotate | Download | only in glsl
      1 /*
      2  * Copyright  2010 Intel Corporation
      3  *
      4  * Permission is hereby granted, free of charge, to any person obtaining a
      5  * copy of this software and associated documentation files (the "Software"),
      6  * to deal in the Software without restriction, including without limitation
      7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      8  * and/or sell copies of the Software, and to permit persons to whom the
      9  * Software is furnished to do so, subject to the following conditions:
     10  *
     11  * The above copyright notice and this permission notice (including the next
     12  * paragraph) shall be included in all copies or substantial portions of the
     13  * Software.
     14  *
     15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
     20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
     21  * DEALINGS IN THE SOFTWARE.
     22  */
     23 
     24 /**
     25  * \file opt_dead_code.cpp
     26  *
     27  * Eliminates dead assignments and variable declarations from the code.
     28  */
     29 
     30 #include "ir.h"
     31 #include "ir_visitor.h"
     32 #include "ir_variable_refcount.h"
     33 #include "compiler/glsl_types.h"
     34 #include "util/hash_table.h"
     35 
     36 static bool debug = false;
     37 
     38 /**
     39  * Do a dead code pass over instructions and everything that instructions
     40  * references.
     41  *
     42  * Note that this will remove assignments to globals, so it is not suitable
     43  * for usage on an unlinked instruction stream.
     44  */
     45 bool
     46 do_dead_code(exec_list *instructions, bool uniform_locations_assigned)
     47 {
     48    ir_variable_refcount_visitor v;
     49    bool progress = false;
     50 
     51    v.run(instructions);
     52 
     53    struct hash_entry *e;
     54    hash_table_foreach(v.ht, e) {
     55       ir_variable_refcount_entry *entry = (ir_variable_refcount_entry *)e->data;
     56 
     57       /* Since each assignment is a reference, the refereneced count must be
     58        * greater than or equal to the assignment count.  If they are equal,
     59        * then all of the references are assignments, and the variable is
     60        * dead.
     61        *
     62        * Note that if the variable is neither assigned nor referenced, both
     63        * counts will be zero and will be caught by the equality test.
     64        */
     65       assert(entry->referenced_count >= entry->assigned_count);
     66 
     67       if (debug) {
     68 	 printf("%s@%p: %d refs, %d assigns, %sdeclared in our scope\n",
     69 		entry->var->name, (void *) entry->var,
     70 		entry->referenced_count, entry->assigned_count,
     71 		entry->declaration ? "" : "not ");
     72       }
     73 
     74       if ((entry->referenced_count > entry->assigned_count)
     75 	  || !entry->declaration)
     76 	 continue;
     77 
     78       /* Section 7.4.1 (Shader Interface Matching) of the OpenGL 4.5
     79        * (Core Profile) spec says:
     80        *
     81        *    "With separable program objects, interfaces between shader
     82        *    stages may involve the outputs from one program object and the
     83        *    inputs from a second program object.  For such interfaces, it is
     84        *    not possible to detect mismatches at link time, because the
     85        *    programs are linked separately. When each such program is
     86        *    linked, all inputs or outputs interfacing with another program
     87        *    stage are treated as active."
     88        */
     89       if (entry->var->data.always_active_io)
     90          continue;
     91 
     92       if (!entry->assign_list.is_empty()) {
     93 	 /* Remove all the dead assignments to the variable we found.
     94 	  * Don't do so if it's a shader or function output, though.
     95 	  */
     96 	 if (entry->var->data.mode != ir_var_function_out &&
     97 	     entry->var->data.mode != ir_var_function_inout &&
     98              entry->var->data.mode != ir_var_shader_out &&
     99              entry->var->data.mode != ir_var_shader_storage) {
    100 
    101             while (!entry->assign_list.is_empty()) {
    102                struct assignment_entry *assignment_entry =
    103                   exec_node_data(struct assignment_entry,
    104                                  entry->assign_list.get_head_raw(), link);
    105 
    106 	       assignment_entry->assign->remove();
    107 
    108 	       if (debug) {
    109 	          printf("Removed assignment to %s@%p\n",
    110 		         entry->var->name, (void *) entry->var);
    111                }
    112 
    113                assignment_entry->link.remove();
    114                free(assignment_entry);
    115             }
    116             progress = true;
    117 	 }
    118       }
    119 
    120       if (entry->assign_list.is_empty()) {
    121 	 /* If there are no assignments or references to the variable left,
    122 	  * then we can remove its declaration.
    123 	  */
    124 
    125 	 /* uniform initializers are precious, and could get used by another
    126 	  * stage.  Also, once uniform locations have been assigned, the
    127 	  * declaration cannot be deleted.
    128 	  */
    129          if (entry->var->data.mode == ir_var_uniform ||
    130              entry->var->data.mode == ir_var_shader_storage) {
    131             if (uniform_locations_assigned || entry->var->constant_initializer)
    132                continue;
    133 
    134             /* Section 2.11.6 (Uniform Variables) of the OpenGL ES 3.0.3 spec
    135              * says:
    136              *
    137              *     "All members of a named uniform block declared with a
    138              *     shared or std140 layout qualifier are considered active,
    139              *     even if they are not referenced in any shader in the
    140              *     program. The uniform block itself is also considered
    141              *     active, even if no member of the block is referenced."
    142              *
    143              * If the variable is in a uniform block with one of those
    144              * layouts, do not eliminate it.
    145              */
    146             if (entry->var->is_in_buffer_block()) {
    147                if (entry->var->get_interface_type_packing() !=
    148                    GLSL_INTERFACE_PACKING_PACKED)
    149                   continue;
    150             }
    151 
    152             if (entry->var->type->is_subroutine())
    153                continue;
    154          }
    155 
    156 	 entry->var->remove();
    157 	 progress = true;
    158 
    159 	 if (debug) {
    160 	    printf("Removed declaration of %s@%p\n",
    161 		   entry->var->name, (void *) entry->var);
    162 	 }
    163       }
    164    }
    165 
    166    return progress;
    167 }
    168 
    169 /**
    170  * Does a dead code pass on the functions present in the instruction stream.
    171  *
    172  * This is suitable for use while the program is not linked, as it will
    173  * ignore variable declarations (and the assignments to them) for variables
    174  * with global scope.
    175  */
    176 bool
    177 do_dead_code_unlinked(exec_list *instructions)
    178 {
    179    bool progress = false;
    180 
    181    foreach_in_list(ir_instruction, ir, instructions) {
    182       ir_function *f = ir->as_function();
    183       if (f) {
    184 	 foreach_in_list(ir_function_signature, sig, &f->signatures) {
    185 	    /* The setting of the uniform_locations_assigned flag here is
    186 	     * irrelevent.  If there is a uniform declaration encountered
    187 	     * inside the body of the function, something has already gone
    188 	     * terribly, terribly wrong.
    189 	     */
    190 	    if (do_dead_code(&sig->body, false))
    191 	       progress = true;
    192 	 }
    193       }
    194    }
    195 
    196    return progress;
    197 }
    198