17d21104a8b92c139051e9a224c5d863802a8ade6Eric Anholt/*
27d21104a8b92c139051e9a224c5d863802a8ade6Eric Anholt * Copyright © 2010 Intel Corporation
37d21104a8b92c139051e9a224c5d863802a8ade6Eric Anholt *
47d21104a8b92c139051e9a224c5d863802a8ade6Eric Anholt * Permission is hereby granted, free of charge, to any person obtaining a
57d21104a8b92c139051e9a224c5d863802a8ade6Eric Anholt * copy of this software and associated documentation files (the "Software"),
67d21104a8b92c139051e9a224c5d863802a8ade6Eric Anholt * to deal in the Software without restriction, including without limitation
77d21104a8b92c139051e9a224c5d863802a8ade6Eric Anholt * the rights to use, copy, modify, merge, publish, distribute, sublicense,
87d21104a8b92c139051e9a224c5d863802a8ade6Eric Anholt * and/or sell copies of the Software, and to permit persons to whom the
97d21104a8b92c139051e9a224c5d863802a8ade6Eric Anholt * Software is furnished to do so, subject to the following conditions:
107d21104a8b92c139051e9a224c5d863802a8ade6Eric Anholt *
117d21104a8b92c139051e9a224c5d863802a8ade6Eric Anholt * The above copyright notice and this permission notice (including the next
127d21104a8b92c139051e9a224c5d863802a8ade6Eric Anholt * paragraph) shall be included in all copies or substantial portions of the
137d21104a8b92c139051e9a224c5d863802a8ade6Eric Anholt * Software.
147d21104a8b92c139051e9a224c5d863802a8ade6Eric Anholt *
157d21104a8b92c139051e9a224c5d863802a8ade6Eric Anholt * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
167d21104a8b92c139051e9a224c5d863802a8ade6Eric Anholt * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
177d21104a8b92c139051e9a224c5d863802a8ade6Eric Anholt * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
187d21104a8b92c139051e9a224c5d863802a8ade6Eric Anholt * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
197d21104a8b92c139051e9a224c5d863802a8ade6Eric Anholt * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
207d21104a8b92c139051e9a224c5d863802a8ade6Eric Anholt * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
217d21104a8b92c139051e9a224c5d863802a8ade6Eric Anholt * DEALINGS IN THE SOFTWARE.
227d21104a8b92c139051e9a224c5d863802a8ade6Eric Anholt */
237d21104a8b92c139051e9a224c5d863802a8ade6Eric Anholt
247d21104a8b92c139051e9a224c5d863802a8ade6Eric Anholt/**
25df883eb1575a740bf91e01cbe2eaa4dbc1f9f154Chad Versace * \file opt_dead_code.cpp
267d21104a8b92c139051e9a224c5d863802a8ade6Eric Anholt *
277d21104a8b92c139051e9a224c5d863802a8ade6Eric Anholt * Eliminates dead assignments and variable declarations from the code.
287d21104a8b92c139051e9a224c5d863802a8ade6Eric Anholt */
297d21104a8b92c139051e9a224c5d863802a8ade6Eric Anholt
307d21104a8b92c139051e9a224c5d863802a8ade6Eric Anholt#include "ir.h"
317d21104a8b92c139051e9a224c5d863802a8ade6Eric Anholt#include "ir_visitor.h"
32d72edc4dddb6dd7908ef0d3f2cec353b028bf6c5Eric Anholt#include "ir_variable_refcount.h"
337d21104a8b92c139051e9a224c5d863802a8ade6Eric Anholt#include "glsl_types.h"
347d21104a8b92c139051e9a224c5d863802a8ade6Eric Anholt
353bd7e70bf7c4a9a52b425284c9f23689f00de93cEric Anholtstatic bool debug = false;
363bd7e70bf7c4a9a52b425284c9f23689f00de93cEric Anholt
377d21104a8b92c139051e9a224c5d863802a8ade6Eric Anholt/**
387d21104a8b92c139051e9a224c5d863802a8ade6Eric Anholt * Do a dead code pass over instructions and everything that instructions
397d21104a8b92c139051e9a224c5d863802a8ade6Eric Anholt * references.
407d21104a8b92c139051e9a224c5d863802a8ade6Eric Anholt *
417d21104a8b92c139051e9a224c5d863802a8ade6Eric Anholt * Note that this will remove assignments to globals, so it is not suitable
427d21104a8b92c139051e9a224c5d863802a8ade6Eric Anholt * for usage on an unlinked instruction stream.
437d21104a8b92c139051e9a224c5d863802a8ade6Eric Anholt */
447d21104a8b92c139051e9a224c5d863802a8ade6Eric Anholtbool
451d5d67f8adac9f94715de9804adb536d9a7ec5eeIan Romanickdo_dead_code(exec_list *instructions, bool uniform_locations_assigned)
467d21104a8b92c139051e9a224c5d863802a8ade6Eric Anholt{
47d72edc4dddb6dd7908ef0d3f2cec353b028bf6c5Eric Anholt   ir_variable_refcount_visitor v;
487d21104a8b92c139051e9a224c5d863802a8ade6Eric Anholt   bool progress = false;
497d21104a8b92c139051e9a224c5d863802a8ade6Eric Anholt
50b5a7cf93442c2def485dcfd05df46abcd78b5d21Ian Romanick   v.run(instructions);
517d21104a8b92c139051e9a224c5d863802a8ade6Eric Anholt
527d21104a8b92c139051e9a224c5d863802a8ade6Eric Anholt   foreach_iter(exec_list_iterator, iter, v.variable_list) {
53e3b520049675f78065eccbc25c001ea77861c129Kenneth Graunke      ir_variable_refcount_entry *entry = (ir_variable_refcount_entry *)iter.get();
547d21104a8b92c139051e9a224c5d863802a8ade6Eric Anholt
55b5a7cf93442c2def485dcfd05df46abcd78b5d21Ian Romanick      /* Since each assignment is a reference, the refereneced count must be
56b5a7cf93442c2def485dcfd05df46abcd78b5d21Ian Romanick       * greater than or equal to the assignment count.  If they are equal,
57b5a7cf93442c2def485dcfd05df46abcd78b5d21Ian Romanick       * then all of the references are assignments, and the variable is
58b5a7cf93442c2def485dcfd05df46abcd78b5d21Ian Romanick       * dead.
59b5a7cf93442c2def485dcfd05df46abcd78b5d21Ian Romanick       *
60b5a7cf93442c2def485dcfd05df46abcd78b5d21Ian Romanick       * Note that if the variable is neither assigned nor referenced, both
61b5a7cf93442c2def485dcfd05df46abcd78b5d21Ian Romanick       * counts will be zero and will be caught by the equality test.
62b5a7cf93442c2def485dcfd05df46abcd78b5d21Ian Romanick       */
63b5a7cf93442c2def485dcfd05df46abcd78b5d21Ian Romanick      assert(entry->referenced_count >= entry->assigned_count);
64b5a7cf93442c2def485dcfd05df46abcd78b5d21Ian Romanick
653bd7e70bf7c4a9a52b425284c9f23689f00de93cEric Anholt      if (debug) {
663bd7e70bf7c4a9a52b425284c9f23689f00de93cEric Anholt	 printf("%s@%p: %d refs, %d assigns, %sdeclared in our scope\n",
679f9386d22aca8d14d1b1e6d4de9b24dcb183ca10Brian Paul		entry->var->name, (void *) entry->var,
683bd7e70bf7c4a9a52b425284c9f23689f00de93cEric Anholt		entry->referenced_count, entry->assigned_count,
693bd7e70bf7c4a9a52b425284c9f23689f00de93cEric Anholt		entry->declaration ? "" : "not ");
703bd7e70bf7c4a9a52b425284c9f23689f00de93cEric Anholt      }
713bd7e70bf7c4a9a52b425284c9f23689f00de93cEric Anholt
72b5a7cf93442c2def485dcfd05df46abcd78b5d21Ian Romanick      if ((entry->referenced_count > entry->assigned_count)
73b5a7cf93442c2def485dcfd05df46abcd78b5d21Ian Romanick	  || !entry->declaration)
747d21104a8b92c139051e9a224c5d863802a8ade6Eric Anholt	 continue;
757d21104a8b92c139051e9a224c5d863802a8ade6Eric Anholt
767d21104a8b92c139051e9a224c5d863802a8ade6Eric Anholt      if (entry->assign) {
777d21104a8b92c139051e9a224c5d863802a8ade6Eric Anholt	 /* Remove a single dead assignment to the variable we found.
787d21104a8b92c139051e9a224c5d863802a8ade6Eric Anholt	  * Don't do so if it's a shader output, though.
797d21104a8b92c139051e9a224c5d863802a8ade6Eric Anholt	  */
80046bef235744e891e4a48076e1a3ff9a61a63092Eric Anholt	 if (entry->var->mode != ir_var_out &&
81d884f60861f270cdcf7d9d47765efcf1e1de30b6Kenneth Graunke	     entry->var->mode != ir_var_inout) {
827d21104a8b92c139051e9a224c5d863802a8ade6Eric Anholt	    entry->assign->remove();
837d21104a8b92c139051e9a224c5d863802a8ade6Eric Anholt	    progress = true;
843bd7e70bf7c4a9a52b425284c9f23689f00de93cEric Anholt
853bd7e70bf7c4a9a52b425284c9f23689f00de93cEric Anholt	    if (debug) {
863bd7e70bf7c4a9a52b425284c9f23689f00de93cEric Anholt	       printf("Removed assignment to %s@%p\n",
879f9386d22aca8d14d1b1e6d4de9b24dcb183ca10Brian Paul		      entry->var->name, (void *) entry->var);
883bd7e70bf7c4a9a52b425284c9f23689f00de93cEric Anholt	    }
897d21104a8b92c139051e9a224c5d863802a8ade6Eric Anholt	 }
907d21104a8b92c139051e9a224c5d863802a8ade6Eric Anholt      } else {
917d21104a8b92c139051e9a224c5d863802a8ade6Eric Anholt	 /* If there are no assignments or references to the variable left,
927d21104a8b92c139051e9a224c5d863802a8ade6Eric Anholt	  * then we can remove its declaration.
937d21104a8b92c139051e9a224c5d863802a8ade6Eric Anholt	  */
947de4d8fe11c53e59265b8a4252ab9940ffcc9929Eric Anholt
957de4d8fe11c53e59265b8a4252ab9940ffcc9929Eric Anholt	 /* uniform initializers are precious, and could get used by another
961d5d67f8adac9f94715de9804adb536d9a7ec5eeIan Romanick	  * stage.  Also, once uniform locations have been assigned, the
971d5d67f8adac9f94715de9804adb536d9a7ec5eeIan Romanick	  * declaration cannot be deleted.
980cea8a56b627cea297e4213266b57b7a1085dccaEric Anholt	  *
990cea8a56b627cea297e4213266b57b7a1085dccaEric Anholt	  * Also, GL_ARB_uniform_buffer_object says that std140
1000cea8a56b627cea297e4213266b57b7a1085dccaEric Anholt	  * uniforms will not be eliminated.  Since we always do
1010cea8a56b627cea297e4213266b57b7a1085dccaEric Anholt	  * std140, just don't eliminate uniforms in UBOs.
1027de4d8fe11c53e59265b8a4252ab9940ffcc9929Eric Anholt	  */
1037de4d8fe11c53e59265b8a4252ab9940ffcc9929Eric Anholt	 if (entry->var->mode == ir_var_uniform &&
1040cea8a56b627cea297e4213266b57b7a1085dccaEric Anholt	     (uniform_locations_assigned ||
1050cea8a56b627cea297e4213266b57b7a1085dccaEric Anholt	      entry->var->constant_value ||
1060cea8a56b627cea297e4213266b57b7a1085dccaEric Anholt	      entry->var->uniform_block != -1))
1077de4d8fe11c53e59265b8a4252ab9940ffcc9929Eric Anholt	    continue;
1087de4d8fe11c53e59265b8a4252ab9940ffcc9929Eric Anholt
1097d21104a8b92c139051e9a224c5d863802a8ade6Eric Anholt	 entry->var->remove();
1107d21104a8b92c139051e9a224c5d863802a8ade6Eric Anholt	 progress = true;
1113bd7e70bf7c4a9a52b425284c9f23689f00de93cEric Anholt
1123bd7e70bf7c4a9a52b425284c9f23689f00de93cEric Anholt	 if (debug) {
1133bd7e70bf7c4a9a52b425284c9f23689f00de93cEric Anholt	    printf("Removed declaration of %s@%p\n",
1149f9386d22aca8d14d1b1e6d4de9b24dcb183ca10Brian Paul		   entry->var->name, (void *) entry->var);
1153bd7e70bf7c4a9a52b425284c9f23689f00de93cEric Anholt	 }
1167d21104a8b92c139051e9a224c5d863802a8ade6Eric Anholt      }
1177d21104a8b92c139051e9a224c5d863802a8ade6Eric Anholt   }
11866d4c65ee2c311ea0c71c39a28456d0c11798d6bEric Anholt
1197d21104a8b92c139051e9a224c5d863802a8ade6Eric Anholt   return progress;
1207d21104a8b92c139051e9a224c5d863802a8ade6Eric Anholt}
1217d21104a8b92c139051e9a224c5d863802a8ade6Eric Anholt
1227d21104a8b92c139051e9a224c5d863802a8ade6Eric Anholt/**
1237d21104a8b92c139051e9a224c5d863802a8ade6Eric Anholt * Does a dead code pass on the functions present in the instruction stream.
1247d21104a8b92c139051e9a224c5d863802a8ade6Eric Anholt *
1257d21104a8b92c139051e9a224c5d863802a8ade6Eric Anholt * This is suitable for use while the program is not linked, as it will
1267d21104a8b92c139051e9a224c5d863802a8ade6Eric Anholt * ignore variable declarations (and the assignments to them) for variables
1277d21104a8b92c139051e9a224c5d863802a8ade6Eric Anholt * with global scope.
1287d21104a8b92c139051e9a224c5d863802a8ade6Eric Anholt */
1297d21104a8b92c139051e9a224c5d863802a8ade6Eric Anholtbool
13066d4c65ee2c311ea0c71c39a28456d0c11798d6bEric Anholtdo_dead_code_unlinked(exec_list *instructions)
1317d21104a8b92c139051e9a224c5d863802a8ade6Eric Anholt{
1327d21104a8b92c139051e9a224c5d863802a8ade6Eric Anholt   bool progress = false;
1337d21104a8b92c139051e9a224c5d863802a8ade6Eric Anholt
1347d21104a8b92c139051e9a224c5d863802a8ade6Eric Anholt   foreach_iter(exec_list_iterator, iter, *instructions) {
1357d21104a8b92c139051e9a224c5d863802a8ade6Eric Anholt      ir_instruction *ir = (ir_instruction *)iter.get();
1366202cbfe3614141e330501959a7322522b35f4e4Kenneth Graunke      ir_function *f = ir->as_function();
1376202cbfe3614141e330501959a7322522b35f4e4Kenneth Graunke      if (f) {
1386202cbfe3614141e330501959a7322522b35f4e4Kenneth Graunke	 foreach_iter(exec_list_iterator, sigiter, *f) {
1396202cbfe3614141e330501959a7322522b35f4e4Kenneth Graunke	    ir_function_signature *sig =
1406202cbfe3614141e330501959a7322522b35f4e4Kenneth Graunke	       (ir_function_signature *) sigiter.get();
1411d5d67f8adac9f94715de9804adb536d9a7ec5eeIan Romanick	    /* The setting of the uniform_locations_assigned flag here is
1421d5d67f8adac9f94715de9804adb536d9a7ec5eeIan Romanick	     * irrelevent.  If there is a uniform declaration encountered
1431d5d67f8adac9f94715de9804adb536d9a7ec5eeIan Romanick	     * inside the body of the function, something has already gone
1441d5d67f8adac9f94715de9804adb536d9a7ec5eeIan Romanick	     * terribly, terribly wrong.
1451d5d67f8adac9f94715de9804adb536d9a7ec5eeIan Romanick	     */
1461d5d67f8adac9f94715de9804adb536d9a7ec5eeIan Romanick	    if (do_dead_code(&sig->body, false))
1476202cbfe3614141e330501959a7322522b35f4e4Kenneth Graunke	       progress = true;
1486202cbfe3614141e330501959a7322522b35f4e4Kenneth Graunke	 }
1497d21104a8b92c139051e9a224c5d863802a8ade6Eric Anholt      }
1507d21104a8b92c139051e9a224c5d863802a8ade6Eric Anholt   }
1517d21104a8b92c139051e9a224c5d863802a8ade6Eric Anholt
1527d21104a8b92c139051e9a224c5d863802a8ade6Eric Anholt   return progress;
1537d21104a8b92c139051e9a224c5d863802a8ade6Eric Anholt}
154