11591693c7b415e9869157c711fe11263c95d74eDavid Li/*
21591693c7b415e9869157c711fe11263c95d74eDavid Li * Copyright © 2010 Intel Corporation
31591693c7b415e9869157c711fe11263c95d74eDavid Li *
41591693c7b415e9869157c711fe11263c95d74eDavid Li * Permission is hereby granted, free of charge, to any person obtaining a
51591693c7b415e9869157c711fe11263c95d74eDavid Li * copy of this software and associated documentation files (the "Software"),
61591693c7b415e9869157c711fe11263c95d74eDavid Li * to deal in the Software without restriction, including without limitation
71591693c7b415e9869157c711fe11263c95d74eDavid Li * the rights to use, copy, modify, merge, publish, distribute, sublicense,
81591693c7b415e9869157c711fe11263c95d74eDavid Li * and/or sell copies of the Software, and to permit persons to whom the
91591693c7b415e9869157c711fe11263c95d74eDavid Li * Software is furnished to do so, subject to the following conditions:
101591693c7b415e9869157c711fe11263c95d74eDavid Li *
111591693c7b415e9869157c711fe11263c95d74eDavid Li * The above copyright notice and this permission notice (including the next
121591693c7b415e9869157c711fe11263c95d74eDavid Li * paragraph) shall be included in all copies or substantial portions of the
131591693c7b415e9869157c711fe11263c95d74eDavid Li * Software.
141591693c7b415e9869157c711fe11263c95d74eDavid Li *
151591693c7b415e9869157c711fe11263c95d74eDavid Li * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
161591693c7b415e9869157c711fe11263c95d74eDavid Li * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
171591693c7b415e9869157c711fe11263c95d74eDavid Li * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
181591693c7b415e9869157c711fe11263c95d74eDavid Li * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
191591693c7b415e9869157c711fe11263c95d74eDavid Li * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
201591693c7b415e9869157c711fe11263c95d74eDavid Li * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
211591693c7b415e9869157c711fe11263c95d74eDavid Li * DEALINGS IN THE SOFTWARE.
221591693c7b415e9869157c711fe11263c95d74eDavid Li */
231591693c7b415e9869157c711fe11263c95d74eDavid Li
241591693c7b415e9869157c711fe11263c95d74eDavid Li/**
251591693c7b415e9869157c711fe11263c95d74eDavid Li * \file opt_dead_code.cpp
261591693c7b415e9869157c711fe11263c95d74eDavid Li *
271591693c7b415e9869157c711fe11263c95d74eDavid Li * Eliminates dead assignments and variable declarations from the code.
281591693c7b415e9869157c711fe11263c95d74eDavid Li */
291591693c7b415e9869157c711fe11263c95d74eDavid Li
301591693c7b415e9869157c711fe11263c95d74eDavid Li#include "ir.h"
311591693c7b415e9869157c711fe11263c95d74eDavid Li#include "ir_visitor.h"
321591693c7b415e9869157c711fe11263c95d74eDavid Li#include "ir_variable_refcount.h"
331591693c7b415e9869157c711fe11263c95d74eDavid Li#include "glsl_types.h"
341591693c7b415e9869157c711fe11263c95d74eDavid Li
351591693c7b415e9869157c711fe11263c95d74eDavid Listatic bool debug = false;
361591693c7b415e9869157c711fe11263c95d74eDavid Li
371591693c7b415e9869157c711fe11263c95d74eDavid Li/**
381591693c7b415e9869157c711fe11263c95d74eDavid Li * Do a dead code pass over instructions and everything that instructions
391591693c7b415e9869157c711fe11263c95d74eDavid Li * references.
401591693c7b415e9869157c711fe11263c95d74eDavid Li *
411591693c7b415e9869157c711fe11263c95d74eDavid Li * Note that this will remove assignments to globals, so it is not suitable
421591693c7b415e9869157c711fe11263c95d74eDavid Li * for usage on an unlinked instruction stream.
431591693c7b415e9869157c711fe11263c95d74eDavid Li */
441591693c7b415e9869157c711fe11263c95d74eDavid Libool
451591693c7b415e9869157c711fe11263c95d74eDavid Lido_dead_code(exec_list *instructions)
461591693c7b415e9869157c711fe11263c95d74eDavid Li{
471591693c7b415e9869157c711fe11263c95d74eDavid Li   ir_variable_refcount_visitor v;
481591693c7b415e9869157c711fe11263c95d74eDavid Li   bool progress = false;
491591693c7b415e9869157c711fe11263c95d74eDavid Li
501591693c7b415e9869157c711fe11263c95d74eDavid Li   v.run(instructions);
511591693c7b415e9869157c711fe11263c95d74eDavid Li
521591693c7b415e9869157c711fe11263c95d74eDavid Li   foreach_iter(exec_list_iterator, iter, v.variable_list) {
531591693c7b415e9869157c711fe11263c95d74eDavid Li      variable_entry *entry = (variable_entry *)iter.get();
541591693c7b415e9869157c711fe11263c95d74eDavid Li
551591693c7b415e9869157c711fe11263c95d74eDavid Li      /* Since each assignment is a reference, the refereneced count must be
561591693c7b415e9869157c711fe11263c95d74eDavid Li       * greater than or equal to the assignment count.  If they are equal,
571591693c7b415e9869157c711fe11263c95d74eDavid Li       * then all of the references are assignments, and the variable is
581591693c7b415e9869157c711fe11263c95d74eDavid Li       * dead.
591591693c7b415e9869157c711fe11263c95d74eDavid Li       *
601591693c7b415e9869157c711fe11263c95d74eDavid Li       * Note that if the variable is neither assigned nor referenced, both
611591693c7b415e9869157c711fe11263c95d74eDavid Li       * counts will be zero and will be caught by the equality test.
621591693c7b415e9869157c711fe11263c95d74eDavid Li       */
631591693c7b415e9869157c711fe11263c95d74eDavid Li      assert(entry->referenced_count >= entry->assigned_count);
641591693c7b415e9869157c711fe11263c95d74eDavid Li
651591693c7b415e9869157c711fe11263c95d74eDavid Li      if (debug) {
661591693c7b415e9869157c711fe11263c95d74eDavid Li	 printf("%s@%p: %d refs, %d assigns, %sdeclared in our scope\n",
671591693c7b415e9869157c711fe11263c95d74eDavid Li		entry->var->name, (void *) entry->var,
681591693c7b415e9869157c711fe11263c95d74eDavid Li		entry->referenced_count, entry->assigned_count,
691591693c7b415e9869157c711fe11263c95d74eDavid Li		entry->declaration ? "" : "not ");
701591693c7b415e9869157c711fe11263c95d74eDavid Li      }
711591693c7b415e9869157c711fe11263c95d74eDavid Li
721591693c7b415e9869157c711fe11263c95d74eDavid Li      if ((entry->referenced_count > entry->assigned_count)
731591693c7b415e9869157c711fe11263c95d74eDavid Li	  || !entry->declaration)
741591693c7b415e9869157c711fe11263c95d74eDavid Li	 continue;
751591693c7b415e9869157c711fe11263c95d74eDavid Li
761591693c7b415e9869157c711fe11263c95d74eDavid Li      if (entry->assign) {
771591693c7b415e9869157c711fe11263c95d74eDavid Li	 /* Remove a single dead assignment to the variable we found.
781591693c7b415e9869157c711fe11263c95d74eDavid Li	  * Don't do so if it's a shader output, though.
791591693c7b415e9869157c711fe11263c95d74eDavid Li	  */
801591693c7b415e9869157c711fe11263c95d74eDavid Li	 if (entry->var->mode != ir_var_out &&
811591693c7b415e9869157c711fe11263c95d74eDavid Li	     entry->var->mode != ir_var_inout &&
821591693c7b415e9869157c711fe11263c95d74eDavid Li	     !ir_has_call(entry->assign)) {
831591693c7b415e9869157c711fe11263c95d74eDavid Li	    entry->assign->remove();
841591693c7b415e9869157c711fe11263c95d74eDavid Li	    progress = true;
851591693c7b415e9869157c711fe11263c95d74eDavid Li
861591693c7b415e9869157c711fe11263c95d74eDavid Li	    if (debug) {
871591693c7b415e9869157c711fe11263c95d74eDavid Li	       printf("Removed assignment to %s@%p\n",
881591693c7b415e9869157c711fe11263c95d74eDavid Li		      entry->var->name, (void *) entry->var);
891591693c7b415e9869157c711fe11263c95d74eDavid Li	    }
901591693c7b415e9869157c711fe11263c95d74eDavid Li	 }
911591693c7b415e9869157c711fe11263c95d74eDavid Li      } else {
921591693c7b415e9869157c711fe11263c95d74eDavid Li	 /* If there are no assignments or references to the variable left,
931591693c7b415e9869157c711fe11263c95d74eDavid Li	  * then we can remove its declaration.
941591693c7b415e9869157c711fe11263c95d74eDavid Li	  */
951591693c7b415e9869157c711fe11263c95d74eDavid Li
961591693c7b415e9869157c711fe11263c95d74eDavid Li	 /* uniform initializers are precious, and could get used by another
971591693c7b415e9869157c711fe11263c95d74eDavid Li	  * stage.
981591693c7b415e9869157c711fe11263c95d74eDavid Li	  */
991591693c7b415e9869157c711fe11263c95d74eDavid Li	 if (entry->var->mode == ir_var_uniform &&
1001591693c7b415e9869157c711fe11263c95d74eDavid Li	     entry->var->constant_value)
1011591693c7b415e9869157c711fe11263c95d74eDavid Li	    continue;
1021591693c7b415e9869157c711fe11263c95d74eDavid Li
1031591693c7b415e9869157c711fe11263c95d74eDavid Li	 entry->var->remove();
1041591693c7b415e9869157c711fe11263c95d74eDavid Li	 progress = true;
1051591693c7b415e9869157c711fe11263c95d74eDavid Li
1061591693c7b415e9869157c711fe11263c95d74eDavid Li	 if (debug) {
1071591693c7b415e9869157c711fe11263c95d74eDavid Li	    printf("Removed declaration of %s@%p\n",
1081591693c7b415e9869157c711fe11263c95d74eDavid Li		   entry->var->name, (void *) entry->var);
1091591693c7b415e9869157c711fe11263c95d74eDavid Li	 }
1101591693c7b415e9869157c711fe11263c95d74eDavid Li      }
1111591693c7b415e9869157c711fe11263c95d74eDavid Li   }
1121591693c7b415e9869157c711fe11263c95d74eDavid Li
1131591693c7b415e9869157c711fe11263c95d74eDavid Li   return progress;
1141591693c7b415e9869157c711fe11263c95d74eDavid Li}
1151591693c7b415e9869157c711fe11263c95d74eDavid Li
1161591693c7b415e9869157c711fe11263c95d74eDavid Li/**
1171591693c7b415e9869157c711fe11263c95d74eDavid Li * Does a dead code pass on the functions present in the instruction stream.
1181591693c7b415e9869157c711fe11263c95d74eDavid Li *
1191591693c7b415e9869157c711fe11263c95d74eDavid Li * This is suitable for use while the program is not linked, as it will
1201591693c7b415e9869157c711fe11263c95d74eDavid Li * ignore variable declarations (and the assignments to them) for variables
1211591693c7b415e9869157c711fe11263c95d74eDavid Li * with global scope.
1221591693c7b415e9869157c711fe11263c95d74eDavid Li */
1231591693c7b415e9869157c711fe11263c95d74eDavid Libool
1241591693c7b415e9869157c711fe11263c95d74eDavid Lido_dead_code_unlinked(exec_list *instructions)
1251591693c7b415e9869157c711fe11263c95d74eDavid Li{
1261591693c7b415e9869157c711fe11263c95d74eDavid Li   bool progress = false;
1271591693c7b415e9869157c711fe11263c95d74eDavid Li
1281591693c7b415e9869157c711fe11263c95d74eDavid Li   foreach_iter(exec_list_iterator, iter, *instructions) {
1291591693c7b415e9869157c711fe11263c95d74eDavid Li      ir_instruction *ir = (ir_instruction *)iter.get();
1301591693c7b415e9869157c711fe11263c95d74eDavid Li      ir_function *f = ir->as_function();
1311591693c7b415e9869157c711fe11263c95d74eDavid Li      if (f) {
1321591693c7b415e9869157c711fe11263c95d74eDavid Li	 foreach_iter(exec_list_iterator, sigiter, *f) {
1331591693c7b415e9869157c711fe11263c95d74eDavid Li	    ir_function_signature *sig =
1341591693c7b415e9869157c711fe11263c95d74eDavid Li	       (ir_function_signature *) sigiter.get();
1351591693c7b415e9869157c711fe11263c95d74eDavid Li	    if (do_dead_code(&sig->body))
1361591693c7b415e9869157c711fe11263c95d74eDavid Li	       progress = true;
1371591693c7b415e9869157c711fe11263c95d74eDavid Li	 }
1381591693c7b415e9869157c711fe11263c95d74eDavid Li      }
1391591693c7b415e9869157c711fe11263c95d74eDavid Li   }
1401591693c7b415e9869157c711fe11263c95d74eDavid Li
1411591693c7b415e9869157c711fe11263c95d74eDavid Li   return progress;
1421591693c7b415e9869157c711fe11263c95d74eDavid Li}
143