blob: 6c346521126e4df7730e049d2f4dd6c3cf4c1ffd [file] [log] [blame]
Eric Anholt5c89f0e2010-05-04 13:04:40 -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/**
Eric Anholtaef0aae2010-05-05 09:38:09 -070025 * \file ir_copy_propagation.cpp
Eric Anholt5c89f0e2010-05-04 13:04:40 -070026 *
Eric Anholtaef0aae2010-05-05 09:38:09 -070027 * 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.
Eric Anholt5c89f0e2010-05-04 13:04:40 -070033 */
34
35#include <stdio.h>
36#include "ir.h"
37#include "ir_visitor.h"
Eric Anholt4e2c0b92010-05-05 09:26:46 -070038#include "ir_print_visitor.h"
Eric Anholt5c89f0e2010-05-04 13:04:40 -070039#include "ir_basic_block.h"
Eric Anholtbdd9b1f2010-05-05 11:45:30 -070040#include "ir_optimization.h"
Eric Anholt5c89f0e2010-05-04 13:04:40 -070041#include "glsl_types.h"
42
43class acp_entry : public exec_node
44{
45public:
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
58class ir_copy_propagation_visitor : public ir_visitor {
59public:
60 ir_copy_propagation_visitor(exec_list *acp)
61 {
62 progress = false;
63 this->acp = acp;
64 }
65
66 /**
67 * \name Visit methods
68 *
69 * As typical for the visitor pattern, there must be one \c visit method for
70 * each concrete subclass of \c ir_instruction. Virtual base classes within
71 * the hierarchy should not have \c visit methods.
72 */
73 /*@{*/
74 virtual void visit(ir_variable *);
75 virtual void visit(ir_loop *);
76 virtual void visit(ir_loop_jump *);
77 virtual void visit(ir_function_signature *);
78 virtual void visit(ir_function *);
79 virtual void visit(ir_expression *);
80 virtual void visit(ir_swizzle *);
81 virtual void visit(ir_dereference *);
82 virtual void visit(ir_assignment *);
83 virtual void visit(ir_constant *);
84 virtual void visit(ir_call *);
85 virtual void visit(ir_return *);
86 virtual void visit(ir_if *);
87 /*@}*/
88
89 /** List of acp_entry */
90 exec_list *acp;
91 bool progress;
92};
93
94
95void
96ir_copy_propagation_visitor::visit(ir_variable *ir)
97{
98 (void)ir;
99}
100
101
102void
103ir_copy_propagation_visitor::visit(ir_loop *ir)
104{
105 (void)ir;
106}
107
108void
109ir_copy_propagation_visitor::visit(ir_loop_jump *ir)
110{
111 (void) ir;
112}
113
114
115void
116ir_copy_propagation_visitor::visit(ir_function_signature *ir)
117{
118 (void)ir;
119}
120
121void
122ir_copy_propagation_visitor::visit(ir_function *ir)
123{
124 (void) ir;
125}
126
127void
128ir_copy_propagation_visitor::visit(ir_expression *ir)
129{
130 unsigned int operand;
131
132 for (operand = 0; operand < ir->get_num_operands(); operand++) {
133 ir->operands[operand]->accept(this);
134 }
135}
136
137
138void
139ir_copy_propagation_visitor::visit(ir_swizzle *ir)
140{
141 ir->val->accept(this);
142}
143
144/**
145 * Replaces dereferences of ACP RHS variables with ACP LHS variables.
146 *
147 * This is where the actual copy propagation occurs. Note that the
148 * rewriting of ir_dereference means that the ir_dereference instance
149 * must not be shared by multiple IR operations!
150 */
151void
152ir_copy_propagation_visitor::visit(ir_dereference *ir)
153{
154 ir_variable *var;
155
156 if (ir->mode == ir_dereference::ir_reference_array) {
157 ir->selector.array_index->accept(this);
158 }
159
160 var = ir->var->as_variable();
161 if (var) {
162 foreach_iter(exec_list_iterator, iter, *this->acp) {
163 acp_entry *entry = (acp_entry *)iter.get();
164
165 if (var == entry->lhs) {
166 ir->var = entry->rhs;
167 this->progress = true;
168 break;
169 }
170 }
171 } else {
172 ir->var->accept(this);
173 }
174}
175
176void
177ir_copy_propagation_visitor::visit(ir_assignment *ir)
178{
179 if (ir->condition)
180 ir->condition->accept(this);
181
182 /* Ignores the LHS. Don't want to rewrite the LHS to point at some
183 * other storage!
184 */
185
186 ir->rhs->accept(this);
187}
188
189
190void
191ir_copy_propagation_visitor::visit(ir_constant *ir)
192{
193 (void) ir;
194}
195
196
197void
198ir_copy_propagation_visitor::visit(ir_call *ir)
199{
200 (void)ir;
201
202 /* Note, if we were to do copy propagation to parameters of calls, we'd
203 * have to be careful about out params.
204 */
205}
206
207
208void
209ir_copy_propagation_visitor::visit(ir_return *ir)
210{
211 ir_rvalue *val = ir->get_value();
212
213 if (val)
214 val->accept(this);
215}
216
217
218void
219ir_copy_propagation_visitor::visit(ir_if *ir)
220{
221 ir->condition->accept(this);
222}
223
Eric Anholt8e75de32010-05-05 09:31:53 -0700224static bool
Eric Anholt5c89f0e2010-05-04 13:04:40 -0700225propagate_copies(ir_instruction *ir, exec_list *acp)
226{
227 ir_copy_propagation_visitor v(acp);
228
229 ir->accept(&v);
Eric Anholt8e75de32010-05-05 09:31:53 -0700230
231 return v.progress;
Eric Anholt5c89f0e2010-05-04 13:04:40 -0700232}
233
234static void
235kill_invalidated_copies(ir_assignment *ir, exec_list *acp)
236{
Eric Anholt4e2c0b92010-05-05 09:26:46 -0700237 ir_instruction *current = ir->lhs;
Eric Anholt5c89f0e2010-05-04 13:04:40 -0700238
Eric Anholt4e2c0b92010-05-05 09:26:46 -0700239 /* Walk down the dereference chain to find the variable at the end
240 * of it that we're actually modifying.
241 */
242 while (current != NULL) {
243 ir_swizzle *swiz;
244 ir_dereference *deref;
Eric Anholt5c89f0e2010-05-04 13:04:40 -0700245
Eric Anholt4e2c0b92010-05-05 09:26:46 -0700246 if ((swiz = current->as_swizzle())) {
247 current = swiz->val;
248 } else if ((deref = current->as_dereference())) {
249 current = deref->var;
250 } else {
251 ir_variable *var = current->as_variable();
252 assert(var);
Eric Anholt5c89f0e2010-05-04 13:04:40 -0700253
Eric Anholt4e2c0b92010-05-05 09:26:46 -0700254 foreach_iter(exec_list_iterator, iter, *acp) {
255 acp_entry *entry = (acp_entry *)iter.get();
256
257 if (entry->lhs == var || entry->rhs == var) {
258 entry->remove();
259 }
Eric Anholt5c89f0e2010-05-04 13:04:40 -0700260 }
Eric Anholt4e2c0b92010-05-05 09:26:46 -0700261 current = NULL;
262 break;
Eric Anholt5c89f0e2010-05-04 13:04:40 -0700263 }
Eric Anholt5c89f0e2010-05-04 13:04:40 -0700264 }
265}
266
267/**
268 * Adds an entry to the available copy list if it's a plain assignment
269 * of a variable to a variable.
270 */
271static void
272add_copy(ir_assignment *ir, exec_list *acp)
273{
274 acp_entry *entry;
275
276 if (ir->condition) {
277 ir_constant *condition = ir->condition->as_constant();
278 if (!condition || !condition->value.b[0])
279 return;
280 }
281
282 ir_dereference *lhs_deref = ir->lhs->as_dereference();
283 if (!lhs_deref || lhs_deref->mode != ir_dereference::ir_reference_variable)
284 return;
285 ir_variable *lhs_var = lhs_deref->var->as_variable();
286
287 ir_dereference *rhs_deref = ir->rhs->as_dereference();
288 if (!rhs_deref || rhs_deref->mode != ir_dereference::ir_reference_variable)
289 return;
290 ir_variable *rhs_var = rhs_deref->var->as_variable();
291
292 entry = new acp_entry(lhs_var, rhs_var);
293 acp->push_tail(entry);
294}
295
296static void
297copy_propagation_basic_block(ir_instruction *first,
Eric Anholt8e75de32010-05-05 09:31:53 -0700298 ir_instruction *last,
299 void *data)
Eric Anholt5c89f0e2010-05-04 13:04:40 -0700300{
301 ir_instruction *ir;
302 /* List of avaialble_copy */
303 exec_list acp;
Eric Anholt8e75de32010-05-05 09:31:53 -0700304 bool *out_progress = (bool *)data;
305 bool progress = false;
Eric Anholt5c89f0e2010-05-04 13:04:40 -0700306
307 for (ir = first;; ir = (ir_instruction *)ir->next) {
308 ir_assignment *ir_assign = ir->as_assignment();
309
Eric Anholt8e75de32010-05-05 09:31:53 -0700310 progress = propagate_copies(ir, &acp) || progress;
Eric Anholt5c89f0e2010-05-04 13:04:40 -0700311
312 if (ir_assign) {
313 kill_invalidated_copies(ir_assign, &acp);
314
315 add_copy(ir_assign, &acp);
316 }
317 if (ir == last)
318 break;
319 }
Eric Anholt8e75de32010-05-05 09:31:53 -0700320 *out_progress = progress;
Eric Anholt5c89f0e2010-05-04 13:04:40 -0700321}
322
323/**
324 * Does a copy propagation pass on the code present in the instruction stream.
325 */
326bool
327do_copy_propagation(exec_list *instructions)
328{
329 bool progress = false;
330
Eric Anholt8e75de32010-05-05 09:31:53 -0700331 call_for_basic_blocks(instructions, copy_propagation_basic_block, &progress);
Eric Anholt5c89f0e2010-05-04 13:04:40 -0700332
Eric Anholt5c89f0e2010-05-04 13:04:40 -0700333 return progress;
334}