scons: Build the new glsl2 code.
[mesa.git] / src / glsl / ir_constant_propagation.cpp
1 /*
2 * Constantright © 2010 Intel Corporation
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * constant 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, constant, 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 constantright 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 CONSTANTRIGHT 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_constant_propagation.cpp
26 *
27 * Tracks assignments of constants to channels of variables, and
28 * usage of those constant channels with direct usage of the constants.
29 *
30 * This can lead to constant folding and algebraic optimizations in
31 * those later expressions, while causing no increase in instruction
32 * count (due to constants being generally free to load from a
33 * constant push buffer or as instruction immediate values) and
34 * possibly reducing register pressure.
35 */
36
37 #include "ir.h"
38 #include "ir_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 *var, unsigned write_mask, ir_constant *constant)
47 {
48 assert(var);
49 assert(constant);
50 this->var = var;
51 this->write_mask = write_mask;
52 this->constant = constant;
53 }
54
55 ir_variable *var;
56 ir_constant *constant;
57 unsigned write_mask;
58 };
59
60
61 class kill_entry : public exec_node
62 {
63 public:
64 kill_entry(ir_variable *var, unsigned write_mask)
65 {
66 assert(var);
67 this->var = var;
68 this->write_mask = write_mask;
69 }
70
71 ir_variable *var;
72 unsigned write_mask;
73 };
74
75 class ir_constant_propagation_visitor : public ir_hierarchical_visitor {
76 public:
77 ir_constant_propagation_visitor()
78 {
79 progress = false;
80 mem_ctx = talloc_new(0);
81 this->acp = new(mem_ctx) exec_list;
82 this->kills = new(mem_ctx) exec_list;
83 }
84 ~ir_constant_propagation_visitor()
85 {
86 talloc_free(mem_ctx);
87 }
88
89 virtual ir_visitor_status visit_enter(class ir_loop *);
90 virtual ir_visitor_status visit_enter(class ir_function_signature *);
91 virtual ir_visitor_status visit_enter(class ir_function *);
92 virtual ir_visitor_status visit_enter(class ir_assignment *);
93 virtual ir_visitor_status visit_leave(class ir_assignment *);
94 virtual ir_visitor_status visit_enter(class ir_expression *);
95 virtual ir_visitor_status visit_enter(class ir_call *);
96 virtual ir_visitor_status visit_enter(class ir_if *);
97 virtual ir_visitor_status visit_enter(class ir_dereference_array *);
98 virtual ir_visitor_status visit_enter(class ir_texture *);
99
100 void add_constant(ir_assignment *ir);
101 void kill(ir_variable *ir, unsigned write_mask);
102 void handle_if_block(exec_list *instructions);
103 void handle_rvalue(ir_rvalue **rvalue);
104
105 /** List of acp_entry: The available constants to propagate */
106 exec_list *acp;
107
108 /**
109 * List of kill_entry: The masks of variables whose values were
110 * killed in this block.
111 */
112 exec_list *kills;
113
114 bool progress;
115
116 bool killed_all;
117
118 void *mem_ctx;
119 };
120
121
122 void
123 ir_constant_propagation_visitor::handle_rvalue(ir_rvalue **rvalue)
124 {
125 if (!*rvalue)
126 return;
127
128 const glsl_type *type = (*rvalue)->type;
129 if (!type->is_scalar() && !type->is_vector())
130 return;
131
132 ir_swizzle *swiz = NULL;
133 ir_dereference_variable *deref = (*rvalue)->as_dereference_variable();
134 if (!deref) {
135 swiz = (*rvalue)->as_swizzle();
136 if (!swiz)
137 return;
138
139 deref = swiz->val->as_dereference_variable();
140 if (!deref)
141 return;
142 }
143
144 ir_constant_data data;
145 memset(&data, 0, sizeof(data));
146
147 for (unsigned int i = 0; i < type->components(); i++) {
148 int channel;
149 acp_entry *found = NULL;
150
151 if (swiz) {
152 switch (i) {
153 case 0: channel = swiz->mask.x; break;
154 case 1: channel = swiz->mask.y; break;
155 case 2: channel = swiz->mask.z; break;
156 case 3: channel = swiz->mask.w; break;
157 default: assert(!"shouldn't be reached"); channel = 0; break;
158 }
159 } else {
160 channel = i;
161 }
162
163 foreach_iter(exec_list_iterator, iter, *this->acp) {
164 acp_entry *entry = (acp_entry *)iter.get();
165 if (entry->var == deref->var && entry->write_mask & (1 << channel)) {
166 found = entry;
167 break;
168 }
169 }
170
171 if (!found)
172 return;
173
174 switch (type->base_type) {
175 case GLSL_TYPE_FLOAT:
176 data.f[i] = found->constant->value.f[channel];
177 break;
178 case GLSL_TYPE_INT:
179 data.i[i] = found->constant->value.i[channel];
180 break;
181 case GLSL_TYPE_UINT:
182 data.u[i] = found->constant->value.u[channel];
183 break;
184 case GLSL_TYPE_BOOL:
185 data.b[i] = found->constant->value.b[channel];
186 break;
187 default:
188 assert(!"not reached");
189 break;
190 }
191 }
192
193 *rvalue = new(talloc_parent(deref)) ir_constant(type, &data);
194 this->progress = true;
195 }
196
197 ir_visitor_status
198 ir_constant_propagation_visitor::visit_enter(ir_function_signature *ir)
199 {
200 /* Treat entry into a function signature as a completely separate
201 * block. Any instructions at global scope will be shuffled into
202 * main() at link time, so they're irrelevant to us.
203 */
204 exec_list *orig_acp = this->acp;
205 exec_list *orig_kills = this->kills;
206 bool orig_killed_all = this->killed_all;
207
208 this->acp = new(mem_ctx) exec_list;
209 this->kills = new(mem_ctx) exec_list;
210 this->killed_all = false;
211
212 visit_list_elements(this, &ir->body);
213
214 this->kills = orig_kills;
215 this->acp = orig_acp;
216 this->killed_all = orig_killed_all;
217
218 return visit_continue_with_parent;
219 }
220
221 ir_visitor_status
222 ir_constant_propagation_visitor::visit_enter(ir_assignment *ir)
223 {
224 handle_rvalue(&ir->condition);
225 handle_rvalue(&ir->rhs);
226
227 return visit_continue;
228 }
229
230 ir_visitor_status
231 ir_constant_propagation_visitor::visit_leave(ir_assignment *ir)
232 {
233 kill(ir->lhs->variable_referenced(), ir->write_mask);
234
235 add_constant(ir);
236
237 return visit_continue;
238 }
239
240 ir_visitor_status
241 ir_constant_propagation_visitor::visit_enter(ir_expression *ir)
242 {
243 for (unsigned int i = 0; i < ir->get_num_operands(); i++) {
244 handle_rvalue(&ir->operands[i]);
245 }
246
247 return visit_continue;
248 }
249
250 ir_visitor_status
251 ir_constant_propagation_visitor::visit_enter(ir_function *ir)
252 {
253 (void) ir;
254 return visit_continue;
255 }
256
257 ir_visitor_status
258 ir_constant_propagation_visitor::visit_enter(ir_call *ir)
259 {
260 /* Do constant propagation on call parameters, but skip any out params */
261 exec_list_iterator sig_param_iter = ir->get_callee()->parameters.iterator();
262 foreach_iter(exec_list_iterator, iter, ir->actual_parameters) {
263 ir_variable *sig_param = (ir_variable *)sig_param_iter.get();
264 ir_rvalue *param = (ir_rvalue *)iter.get();
265 if (sig_param->mode != ir_var_out && sig_param->mode != ir_var_inout) {
266 ir_rvalue *new_param = param;
267 handle_rvalue(&new_param);
268 if (new_param != param)
269 param->replace_with(new_param);
270 else
271 param->accept(this);
272 }
273 sig_param_iter.next();
274 }
275
276 /* Since we're unlinked, we don't (necssarily) know the side effects of
277 * this call. So kill all copies.
278 */
279 acp->make_empty();
280 this->killed_all = true;
281
282 return visit_continue_with_parent;
283 }
284
285 void
286 ir_constant_propagation_visitor::handle_if_block(exec_list *instructions)
287 {
288 exec_list *orig_acp = this->acp;
289 exec_list *orig_kills = this->kills;
290 bool orig_killed_all = this->killed_all;
291
292 this->acp = new(mem_ctx) exec_list;
293 this->kills = new(mem_ctx) exec_list;
294 this->killed_all = false;
295
296 /* Populate the initial acp with a constant of the original */
297 foreach_iter(exec_list_iterator, iter, *orig_acp) {
298 acp_entry *a = (acp_entry *)iter.get();
299 this->acp->push_tail(new(this->mem_ctx) acp_entry(a->var, a->write_mask,
300 a->constant));
301 }
302
303 visit_list_elements(this, instructions);
304
305 if (this->killed_all) {
306 orig_acp->make_empty();
307 }
308
309 exec_list *new_kills = this->kills;
310 this->kills = orig_kills;
311 this->acp = orig_acp;
312 this->killed_all = this->killed_all || orig_killed_all;
313
314 foreach_iter(exec_list_iterator, iter, *new_kills) {
315 kill_entry *k = (kill_entry *)iter.get();
316 kill(k->var, k->write_mask);
317 }
318 }
319
320 ir_visitor_status
321 ir_constant_propagation_visitor::visit_enter(ir_if *ir)
322 {
323 ir->condition->accept(this);
324 handle_rvalue(&ir->condition);
325
326 handle_if_block(&ir->then_instructions);
327 handle_if_block(&ir->else_instructions);
328
329 /* handle_if_block() already descended into the children. */
330 return visit_continue_with_parent;
331 }
332
333 ir_visitor_status
334 ir_constant_propagation_visitor::visit_enter(ir_dereference_array *ir)
335 {
336 handle_rvalue(&ir->array_index);
337 return visit_continue;
338 }
339
340 ir_visitor_status
341 ir_constant_propagation_visitor::visit_enter(ir_texture *ir)
342 {
343 handle_rvalue(&ir->coordinate);
344 handle_rvalue(&ir->projector);
345 handle_rvalue(&ir->shadow_comparitor);
346
347 switch (ir->op) {
348 case ir_tex:
349 break;
350 case ir_txb:
351 handle_rvalue(&ir->lod_info.bias);
352 break;
353 case ir_txf:
354 case ir_txl:
355 handle_rvalue(&ir->lod_info.lod);
356 break;
357 case ir_txd:
358 handle_rvalue(&ir->lod_info.grad.dPdx);
359 handle_rvalue(&ir->lod_info.grad.dPdy);
360 break;
361 }
362
363 return visit_continue;
364 }
365
366 ir_visitor_status
367 ir_constant_propagation_visitor::visit_enter(ir_loop *ir)
368 {
369 exec_list *orig_acp = this->acp;
370 exec_list *orig_kills = this->kills;
371 bool orig_killed_all = this->killed_all;
372
373 /* FINISHME: For now, the initial acp for loops is totally empty.
374 * We could go through once, then go through again with the acp
375 * cloned minus the killed entries after the first run through.
376 */
377 this->acp = new(mem_ctx) exec_list;
378 this->kills = new(mem_ctx) exec_list;
379 this->killed_all = false;
380
381 visit_list_elements(this, &ir->body_instructions);
382
383 if (this->killed_all) {
384 orig_acp->make_empty();
385 }
386
387 exec_list *new_kills = this->kills;
388 this->kills = orig_kills;
389 this->acp = orig_acp;
390 this->killed_all = this->killed_all || orig_killed_all;
391
392 foreach_iter(exec_list_iterator, iter, *new_kills) {
393 kill_entry *k = (kill_entry *)iter.get();
394 kill(k->var, k->write_mask);
395 }
396
397 /* already descended into the children. */
398 return visit_continue_with_parent;
399 }
400
401 void
402 ir_constant_propagation_visitor::kill(ir_variable *var, unsigned write_mask)
403 {
404 assert(var != NULL);
405
406 /* We don't track non-vectors. */
407 if (!var->type->is_vector() && !var->type->is_scalar())
408 return;
409
410 /* Remove any entries currently in the ACP for this kill. */
411 foreach_iter(exec_list_iterator, iter, *this->acp) {
412 acp_entry *entry = (acp_entry *)iter.get();
413
414 if (entry->var == var) {
415 entry->write_mask &= ~write_mask;
416 if (entry->write_mask == 0)
417 entry->remove();
418 }
419 }
420
421 /* Add this writemask of the variable to the list of killed
422 * variables in this block.
423 */
424 foreach_iter(exec_list_iterator, iter, *this->kills) {
425 kill_entry *entry = (kill_entry *)iter.get();
426
427 if (entry->var == var) {
428 entry->write_mask |= write_mask;
429 return;
430 }
431 }
432 /* Not already in the list. Make new entry. */
433 this->kills->push_tail(new(this->mem_ctx) kill_entry(var, write_mask));
434 }
435
436 /**
437 * Adds an entry to the available constant list if it's a plain assignment
438 * of a variable to a variable.
439 */
440 void
441 ir_constant_propagation_visitor::add_constant(ir_assignment *ir)
442 {
443 acp_entry *entry;
444
445 if (ir->condition) {
446 ir_constant *condition = ir->condition->as_constant();
447 if (!condition || !condition->value.b[0])
448 return;
449 }
450
451 if (!ir->write_mask)
452 return;
453
454 ir_dereference_variable *deref = ir->lhs->as_dereference_variable();
455 ir_constant *constant = ir->rhs->as_constant();
456
457 if (!deref || !constant)
458 return;
459
460 /* Only do constant propagation on vectors. Constant matrices,
461 * arrays, or structures would require more work elsewhere.
462 */
463 if (!deref->var->type->is_vector() && !deref->var->type->is_scalar())
464 return;
465
466 entry = new(this->mem_ctx) acp_entry(deref->var, ir->write_mask, constant);
467 this->acp->push_tail(entry);
468 }
469
470 /**
471 * Does a constant propagation pass on the code present in the instruction stream.
472 */
473 bool
474 do_constant_propagation(exec_list *instructions)
475 {
476 ir_constant_propagation_visitor v;
477
478 visit_list_elements(&v, instructions);
479
480 return v.progress;
481 }