blob: 51fa96df0cc5d1abf1e8183ea24be450c132e1c3 [file] [log] [blame]
Eric Anholt7d211042010-04-16 16:43:47 -07001/*
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 ir_dead_code.cpp
26 *
27 * Eliminates dead assignments and variable declarations from the code.
28 */
29
Eric Anholt7d211042010-04-16 16:43:47 -070030#include "ir.h"
31#include "ir_visitor.h"
32#include "ir_expression_flattening.h"
33#include "glsl_types.h"
34
35class variable_entry : public exec_node
36{
37public:
38 variable_entry(ir_variable *var)
39 {
40 this->var = var;
41 assign = NULL;
Ian Romanickb5a7cf92010-05-14 12:41:22 -070042 referenced_count = 0;
43 assigned_count = 0;
Eric Anholt7d211042010-04-16 16:43:47 -070044 declaration = false;
45 }
46
47 ir_variable *var; /* The key: the variable's pointer. */
48 ir_assignment *assign; /* An assignment to the variable, if any */
Ian Romanickb5a7cf92010-05-14 12:41:22 -070049
50 /** Number of times the variable is referenced, including assignments. */
51 unsigned referenced_count;
52
53 /** Number of times the variable is assignmened. */
54 unsigned assigned_count;
55
Eric Anholt7d211042010-04-16 16:43:47 -070056 bool declaration; /* If the variable had a decl in the instruction stream */
57};
58
Ian Romanickb5a7cf92010-05-14 12:41:22 -070059class ir_dead_code_visitor : public ir_hierarchical_visitor {
Eric Anholt7d211042010-04-16 16:43:47 -070060public:
Ian Romanickb5a7cf92010-05-14 12:41:22 -070061 virtual ir_visitor_status visit(ir_variable *);
Ian Romanickf3a002b2010-05-19 12:02:19 +020062 virtual ir_visitor_status visit(ir_dereference_variable *);
Eric Anholt7d211042010-04-16 16:43:47 -070063
Ian Romanickb5a7cf92010-05-14 12:41:22 -070064 virtual ir_visitor_status visit_enter(ir_function *);
Ian Romanickb5a7cf92010-05-14 12:41:22 -070065 virtual ir_visitor_status visit_leave(ir_assignment *);
66
Eric Anholt7d211042010-04-16 16:43:47 -070067 variable_entry *get_variable_entry(ir_variable *var);
68
69 bool (*predicate)(ir_instruction *ir);
70 ir_instruction *base_ir;
71
72 /* List of variable_entry */
73 exec_list variable_list;
Eric Anholtbda27422010-06-25 13:38:38 -070074
75 void *mem_ctx;
Eric Anholt7d211042010-04-16 16:43:47 -070076};
77
Ian Romanickb5a7cf92010-05-14 12:41:22 -070078
Eric Anholt7d211042010-04-16 16:43:47 -070079variable_entry *
80ir_dead_code_visitor::get_variable_entry(ir_variable *var)
81{
82 assert(var);
83 foreach_iter(exec_list_iterator, iter, this->variable_list) {
84 variable_entry *entry = (variable_entry *)iter.get();
85 if (entry->var == var)
86 return entry;
87 }
88
Eric Anholtbda27422010-06-25 13:38:38 -070089 variable_entry *entry = new(mem_ctx) variable_entry(var);
Eric Anholt7d211042010-04-16 16:43:47 -070090 this->variable_list.push_tail(entry);
91 return entry;
92}
93
Eric Anholt7d211042010-04-16 16:43:47 -070094
Ian Romanickb5a7cf92010-05-14 12:41:22 -070095ir_visitor_status
Eric Anholt7d211042010-04-16 16:43:47 -070096ir_dead_code_visitor::visit(ir_variable *ir)
97{
98 variable_entry *entry = this->get_variable_entry(ir);
Ian Romanickf3a002b2010-05-19 12:02:19 +020099 if (entry)
100 entry->declaration = true;
101
102 return visit_continue;
103}
104
105
106ir_visitor_status
107ir_dead_code_visitor::visit(ir_dereference_variable *ir)
108{
109 ir_variable *const var = ir->variable_referenced();
110 variable_entry *entry = this->get_variable_entry(var);
111
112 if (entry)
113 entry->referenced_count++;
Ian Romanickb5a7cf92010-05-14 12:41:22 -0700114
115 return visit_continue;
Eric Anholt7d211042010-04-16 16:43:47 -0700116}
117
118
Ian Romanickb5a7cf92010-05-14 12:41:22 -0700119ir_visitor_status
120ir_dead_code_visitor::visit_enter(ir_function *ir)
Eric Anholt7d211042010-04-16 16:43:47 -0700121{
122 (void) ir;
Ian Romanickb5a7cf92010-05-14 12:41:22 -0700123 return visit_continue_with_parent;
Eric Anholt7d211042010-04-16 16:43:47 -0700124}
125
126
Ian Romanickb5a7cf92010-05-14 12:41:22 -0700127ir_visitor_status
Ian Romanickb5a7cf92010-05-14 12:41:22 -0700128ir_dead_code_visitor::visit_leave(ir_assignment *ir)
Eric Anholt7d211042010-04-16 16:43:47 -0700129{
Eric Anholt7d211042010-04-16 16:43:47 -0700130 variable_entry *entry;
Ian Romanick461c2942010-05-18 13:53:20 +0200131 entry = this->get_variable_entry(ir->lhs->variable_referenced());
Eric Anholt7d211042010-04-16 16:43:47 -0700132 if (entry) {
Ian Romanickb5a7cf92010-05-14 12:41:22 -0700133 entry->assigned_count++;
Eric Anholt7d211042010-04-16 16:43:47 -0700134 if (entry->assign == NULL)
135 entry->assign = ir;
136 }
Ian Romanickb5a7cf92010-05-14 12:41:22 -0700137
138 return visit_continue;
Eric Anholt7d211042010-04-16 16:43:47 -0700139}
140
141
Eric Anholt7d211042010-04-16 16:43:47 -0700142/**
143 * Do a dead code pass over instructions and everything that instructions
144 * references.
145 *
146 * Note that this will remove assignments to globals, so it is not suitable
147 * for usage on an unlinked instruction stream.
148 */
149bool
Eric Anholtbda27422010-06-25 13:38:38 -0700150do_dead_code(struct _mesa_glsl_parse_state *state,
151 exec_list *instructions)
Eric Anholt7d211042010-04-16 16:43:47 -0700152{
153 ir_dead_code_visitor v;
154 bool progress = false;
155
Eric Anholtbda27422010-06-25 13:38:38 -0700156 v.mem_ctx = state;
Ian Romanickb5a7cf92010-05-14 12:41:22 -0700157 v.run(instructions);
Eric Anholt7d211042010-04-16 16:43:47 -0700158
159 foreach_iter(exec_list_iterator, iter, v.variable_list) {
160 variable_entry *entry = (variable_entry *)iter.get();
161
Ian Romanickb5a7cf92010-05-14 12:41:22 -0700162 /* Since each assignment is a reference, the refereneced count must be
163 * greater than or equal to the assignment count. If they are equal,
164 * then all of the references are assignments, and the variable is
165 * dead.
166 *
167 * Note that if the variable is neither assigned nor referenced, both
168 * counts will be zero and will be caught by the equality test.
169 */
170 assert(entry->referenced_count >= entry->assigned_count);
171
172 if ((entry->referenced_count > entry->assigned_count)
173 || !entry->declaration)
Eric Anholt7d211042010-04-16 16:43:47 -0700174 continue;
175
176 if (entry->assign) {
177 /* Remove a single dead assignment to the variable we found.
178 * Don't do so if it's a shader output, though.
179 */
180 if (!entry->var->shader_out) {
181 entry->assign->remove();
182 progress = true;
183 }
184 } else {
185 /* If there are no assignments or references to the variable left,
186 * then we can remove its declaration.
187 */
188 entry->var->remove();
189 progress = true;
190 }
191 }
192 return progress;
193}
194
195/**
196 * Does a dead code pass on the functions present in the instruction stream.
197 *
198 * This is suitable for use while the program is not linked, as it will
199 * ignore variable declarations (and the assignments to them) for variables
200 * with global scope.
201 */
202bool
Eric Anholtbda27422010-06-25 13:38:38 -0700203do_dead_code_unlinked(struct _mesa_glsl_parse_state *state,
204 exec_list *instructions)
Eric Anholt7d211042010-04-16 16:43:47 -0700205{
206 bool progress = false;
207
208 foreach_iter(exec_list_iterator, iter, *instructions) {
209 ir_instruction *ir = (ir_instruction *)iter.get();
Kenneth Graunke6202cbf2010-04-21 16:02:15 -0700210 ir_function *f = ir->as_function();
211 if (f) {
212 foreach_iter(exec_list_iterator, sigiter, *f) {
213 ir_function_signature *sig =
214 (ir_function_signature *) sigiter.get();
Eric Anholtbda27422010-06-25 13:38:38 -0700215 if (do_dead_code(state, &sig->body))
Kenneth Graunke6202cbf2010-04-21 16:02:15 -0700216 progress = true;
217 }
Eric Anholt7d211042010-04-16 16:43:47 -0700218 }
219 }
220
221 return progress;
222}