ir_constant_visitor: Handle dereferences of constant records
[mesa.git] / ir_copy_propagation.cpp
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 ir_copy_propagation.cpp
26 *
27 * Moves usage of recently-copied variables to the previous copy of
28 * the variable within basic blocks.
29 *
30 * This should reduce the number of MOV instructions in the generated
31 * programs unless copy propagation is also done on the LIR, and may
32 * help anyway by triggering other optimizations that live in the HIR.
33 */
34
35 #include <stdio.h>
36 #include "ir.h"
37 #include "ir_visitor.h"
38 #include "ir_print_visitor.h"
39 #include "ir_basic_block.h"
40 #include "ir_optimization.h"
41 #include "glsl_types.h"
42
43 class acp_entry : public exec_node
44 {
45 public:
46 acp_entry(ir_variable *lhs, ir_variable *rhs)
47 {
48 assert(lhs);
49 assert(rhs);
50 this->lhs = lhs;
51 this->rhs = rhs;
52 }
53
54 ir_variable *lhs;
55 ir_variable *rhs;
56 };
57
58 class ir_copy_propagation_visitor : public ir_hierarchical_visitor {
59 public:
60 ir_copy_propagation_visitor(exec_list *acp)
61 {
62 progress = false;
63 in_lhs = false;
64 this->acp = acp;
65 }
66
67 virtual ir_visitor_status visit(class ir_dereference_variable *);
68 virtual ir_visitor_status visit_enter(class ir_loop *);
69 virtual ir_visitor_status visit_enter(class ir_function_signature *);
70 virtual ir_visitor_status visit_enter(class ir_function *);
71 virtual ir_visitor_status visit_enter(class ir_assignment *);
72 virtual ir_visitor_status visit_enter(class ir_call *);
73 virtual ir_visitor_status visit_enter(class ir_if *);
74
75 /** List of acp_entry */
76 exec_list *acp;
77 bool progress;
78
79 /** Currently in the LHS of an assignment? */
80 bool in_lhs;
81 };
82
83
84 ir_visitor_status
85 ir_copy_propagation_visitor::visit_enter(ir_loop *ir)
86 {
87 (void)ir;
88 return visit_continue_with_parent;
89 }
90
91 ir_visitor_status
92 ir_copy_propagation_visitor::visit_enter(ir_function_signature *ir)
93 {
94 (void)ir;
95 return visit_continue_with_parent;
96 }
97
98 ir_visitor_status
99 ir_copy_propagation_visitor::visit_enter(ir_assignment *ir)
100 {
101 (void) ir;
102 this->in_lhs = true;
103 return visit_continue;
104 }
105
106 ir_visitor_status
107 ir_copy_propagation_visitor::visit_enter(ir_function *ir)
108 {
109 (void) ir;
110 return visit_continue_with_parent;
111 }
112
113 /**
114 * Replaces dereferences of ACP RHS variables with ACP LHS variables.
115 *
116 * This is where the actual copy propagation occurs. Note that the
117 * rewriting of ir_dereference means that the ir_dereference instance
118 * must not be shared by multiple IR operations!
119 */
120 ir_visitor_status
121 ir_copy_propagation_visitor::visit(ir_dereference_variable *ir)
122 {
123 /* Ignores the LHS. Don't want to rewrite the LHS to point at some
124 * other storage!
125 */
126 if (this->in_lhs) {
127 this->in_lhs = false;
128 return visit_continue;
129 }
130
131 ir_variable *var = ir->variable_referenced();
132
133 foreach_iter(exec_list_iterator, iter, *this->acp) {
134 acp_entry *entry = (acp_entry *)iter.get();
135
136 if (var == entry->lhs) {
137 ir->var = entry->rhs;
138 this->progress = true;
139 break;
140 }
141 }
142
143 return visit_continue;
144 }
145
146
147 ir_visitor_status
148 ir_copy_propagation_visitor::visit_enter(ir_call *ir)
149 {
150 (void)ir;
151
152 /* Note, if we were to do copy propagation to parameters of calls, we'd
153 * have to be careful about out params.
154 */
155 return visit_continue_with_parent;
156 }
157
158
159 ir_visitor_status
160 ir_copy_propagation_visitor::visit_enter(ir_if *ir)
161 {
162 ir->condition->accept(this);
163
164 /* Do not traverse into the body of the if-statement since that is a
165 * different basic block.
166 */
167 return visit_continue_with_parent;
168 }
169
170 static bool
171 propagate_copies(ir_instruction *ir, exec_list *acp)
172 {
173 ir_copy_propagation_visitor v(acp);
174
175 ir->accept(&v);
176
177 return v.progress;
178 }
179
180 static void
181 kill_invalidated_copies(ir_assignment *ir, exec_list *acp)
182 {
183 ir_variable *var = ir->lhs->variable_referenced();
184 assert(var != NULL);
185
186 foreach_iter(exec_list_iterator, iter, *acp) {
187 acp_entry *entry = (acp_entry *)iter.get();
188
189 if (entry->lhs == var || entry->rhs == var) {
190 entry->remove();
191 }
192 }
193 }
194
195 /**
196 * Adds an entry to the available copy list if it's a plain assignment
197 * of a variable to a variable.
198 */
199 static void
200 add_copy(ir_assignment *ir, exec_list *acp)
201 {
202 acp_entry *entry;
203
204 if (ir->condition) {
205 ir_constant *condition = ir->condition->as_constant();
206 if (!condition || !condition->value.b[0])
207 return;
208 }
209
210 ir_variable *lhs_var = ir->lhs->whole_variable_referenced();
211 ir_variable *rhs_var = ir->rhs->whole_variable_referenced();
212
213 if ((lhs_var != NULL) && (rhs_var != NULL)) {
214 entry = new acp_entry(lhs_var, rhs_var);
215 acp->push_tail(entry);
216 }
217 }
218
219 static void
220 copy_propagation_basic_block(ir_instruction *first,
221 ir_instruction *last,
222 void *data)
223 {
224 ir_instruction *ir;
225 /* List of avaialble_copy */
226 exec_list acp;
227 bool *out_progress = (bool *)data;
228 bool progress = false;
229
230 for (ir = first;; ir = (ir_instruction *)ir->next) {
231 ir_assignment *ir_assign = ir->as_assignment();
232
233 progress = propagate_copies(ir, &acp) || progress;
234
235 if (ir_assign) {
236 kill_invalidated_copies(ir_assign, &acp);
237
238 add_copy(ir_assign, &acp);
239 }
240 if (ir == last)
241 break;
242 }
243 *out_progress = progress;
244 }
245
246 /**
247 * Does a copy propagation pass on the code present in the instruction stream.
248 */
249 bool
250 do_copy_propagation(exec_list *instructions)
251 {
252 bool progress = false;
253
254 call_for_basic_blocks(instructions, copy_propagation_basic_block, &progress);
255
256 return progress;
257 }