2 * Copyright © 2010 Intel Corporation
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:
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
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.
25 * \file ir_dead_code_local.cpp
27 * Eliminates local dead assignments from the code.
29 * This operates on basic blocks, tracking assignments and finding if
30 * they're used before the variable is completely reassigned.
32 * Compare this to ir_dead_code.cpp, which operates globally looking
33 * for assignments to variables that are never read.
38 #include "ir_visitor.h"
39 #include "ir_print_visitor.h"
40 #include "ir_basic_block.h"
41 #include "ir_visit_tree.h"
42 #include "ir_optimization.h"
43 #include "glsl_types.h"
45 static bool debug
= false;
47 class assignment_entry
: public exec_node
50 assignment_entry(ir_variable
*lhs
, ir_instruction
*ir
)
63 ir_kill_for_derefs_callback(ir_instruction
*ir
, void *data
)
65 exec_list
*assignments
= (exec_list
*)data
;
66 ir_variable
*var
= ir
->as_variable();
71 foreach_iter(exec_list_iterator
, iter
, *assignments
) {
72 assignment_entry
*entry
= (assignment_entry
*)iter
.get();
74 if (entry
->lhs
== var
) {
76 printf("kill %s\n", entry
->lhs
->name
);
83 kill_for_derefs(ir_instruction
*ir
, exec_list
*assignments
)
85 ir_visit_tree(ir
, ir_kill_for_derefs_callback
, assignments
);
89 * Adds an entry to the available copy list if it's a plain assignment
90 * of a variable to a variable.
93 process_assignment(ir_assignment
*ir
, exec_list
*assignments
)
95 ir_variable
*var
= NULL
;
96 bool progress
= false;
97 ir_instruction
*current
;
99 /* Kill assignment entries for things used to produce this assignment. */
100 kill_for_derefs(ir
->rhs
, assignments
);
102 kill_for_derefs(ir
->condition
, assignments
);
105 /* Walk down the dereference chain to find the variable at the end
106 * of it that we're actually modifying. Kill assignment enties used as
107 * array indices, too.
109 for (current
= ir
->lhs
; current
!= NULL
;) {
111 ir_dereference
*deref
;
113 if ((swiz
= current
->as_swizzle())) {
115 } else if ((deref
= current
->as_dereference())) {
116 if (deref
->mode
== ir_dereference::ir_reference_array
)
117 kill_for_derefs(deref
->selector
.array_index
, assignments
);
118 current
= deref
->var
;
120 var
= current
->as_variable();
129 bool always_assign
= true;
131 ir_constant
*condition
= ir
->condition
->as_constant();
132 if (!condition
|| !condition
->value
.b
[0])
133 always_assign
= false;
136 /* Now, check if we did a whole-variable assignment. */
137 ir_dereference
*lhs_deref
= ir
->lhs
->as_dereference();
140 lhs_deref
->mode
== ir_dereference::ir_reference_variable
) {
141 /* We did a whole-variable assignment. So, any instruction in
142 * the assignment list with the same LHS is dead.
145 printf("looking for %s to remove\n", var
->name
);
146 foreach_iter(exec_list_iterator
, iter
, *assignments
) {
147 assignment_entry
*entry
= (assignment_entry
*)iter
.get();
149 if (entry
->lhs
== var
) {
151 printf("removing %s\n", var
->name
);
159 /* Add this instruction to the assignment list. */
160 assignment_entry
*entry
= new assignment_entry(var
, ir
);
161 assignments
->push_tail(entry
);
164 printf("add %s\n", var
->name
);
166 printf("current entries\n");
167 foreach_iter(exec_list_iterator
, iter
, *assignments
) {
168 assignment_entry
*entry
= (assignment_entry
*)iter
.get();
170 printf(" %s\n", entry
->lhs
->name
);
178 dead_code_local_basic_block(ir_instruction
*first
,
179 ir_instruction
*last
,
182 ir_instruction
*ir
, *ir_next
;
183 /* List of avaialble_copy */
184 exec_list assignments
;
185 bool *out_progress
= (bool *)data
;
186 bool progress
= false;
188 /* Safe looping, since process_assignment */
189 for (ir
= first
, ir_next
= (ir_instruction
*)first
->next
;;
190 ir
= ir_next
, ir_next
= (ir_instruction
*)ir
->next
) {
191 ir_assignment
*ir_assign
= ir
->as_assignment();
200 progress
= process_assignment(ir_assign
, &assignments
) || progress
;
202 kill_for_derefs(ir
, &assignments
);
208 *out_progress
= progress
;
212 * Does a copy propagation pass on the code present in the instruction stream.
215 do_dead_code_local(exec_list
*instructions
)
217 bool progress
= false;
219 call_for_basic_blocks(instructions
, dead_code_local_basic_block
, &progress
);