OSDN Git Service

glsl: add a few missing int64 constant propagation cases
[android-x86/external-mesa.git] / src / compiler / glsl / opt_constant_propagation.cpp
1 /*
2  * Copyright © 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 opt_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_rvalue_visitor.h"
40 #include "ir_basic_block.h"
41 #include "ir_optimization.h"
42 #include "compiler/glsl_types.h"
43 #include "util/hash_table.h"
44
45 namespace {
46
47 class acp_entry : public exec_node
48 {
49 public:
50    /* override operator new from exec_node */
51    DECLARE_LINEAR_ZALLOC_CXX_OPERATORS(acp_entry)
52
53    acp_entry(ir_variable *var, unsigned write_mask, ir_constant *constant)
54    {
55       assert(var);
56       assert(constant);
57       this->var = var;
58       this->write_mask = write_mask;
59       this->constant = constant;
60       this->initial_values = write_mask;
61    }
62
63    acp_entry(const acp_entry *src)
64    {
65       this->var = src->var;
66       this->write_mask = src->write_mask;
67       this->constant = src->constant;
68       this->initial_values = src->initial_values;
69    }
70
71    ir_variable *var;
72    ir_constant *constant;
73    unsigned write_mask;
74
75    /** Mask of values initially available in the constant. */
76    unsigned initial_values;
77 };
78
79
80 class kill_entry : public exec_node
81 {
82 public:
83    /* override operator new from exec_node */
84    DECLARE_LINEAR_ZALLOC_CXX_OPERATORS(kill_entry)
85
86    kill_entry(ir_variable *var, unsigned write_mask)
87    {
88       assert(var);
89       this->var = var;
90       this->write_mask = write_mask;
91    }
92
93    ir_variable *var;
94    unsigned write_mask;
95 };
96
97 class ir_constant_propagation_visitor : public ir_rvalue_visitor {
98 public:
99    ir_constant_propagation_visitor()
100    {
101       progress = false;
102       killed_all = false;
103       mem_ctx = ralloc_context(0);
104       this->lin_ctx = linear_alloc_parent(this->mem_ctx, 0);
105       this->acp = new(mem_ctx) exec_list;
106       this->kills = _mesa_hash_table_create(mem_ctx, _mesa_hash_pointer,
107                                             _mesa_key_pointer_equal);
108    }
109    ~ir_constant_propagation_visitor()
110    {
111       ralloc_free(mem_ctx);
112    }
113
114    virtual ir_visitor_status visit_enter(class ir_loop *);
115    virtual ir_visitor_status visit_enter(class ir_function_signature *);
116    virtual ir_visitor_status visit_enter(class ir_function *);
117    virtual ir_visitor_status visit_leave(class ir_assignment *);
118    virtual ir_visitor_status visit_enter(class ir_call *);
119    virtual ir_visitor_status visit_enter(class ir_if *);
120
121    void add_constant(ir_assignment *ir);
122    void constant_folding(ir_rvalue **rvalue);
123    void constant_propagation(ir_rvalue **rvalue);
124    void kill(ir_variable *ir, unsigned write_mask);
125    void handle_if_block(exec_list *instructions);
126    void handle_rvalue(ir_rvalue **rvalue);
127
128    /** List of acp_entry: The available constants to propagate */
129    exec_list *acp;
130
131    /**
132     * Hash table of kill_entry: The masks of variables whose values were
133     * killed in this block.
134     */
135    hash_table *kills;
136
137    bool progress;
138
139    bool killed_all;
140
141    void *mem_ctx;
142    void *lin_ctx;
143 };
144
145
146 void
147 ir_constant_propagation_visitor::constant_folding(ir_rvalue **rvalue)
148 {
149    if (this->in_assignee || *rvalue == NULL)
150       return;
151
152    if (ir_constant_fold(rvalue))
153       this->progress = true;
154
155    ir_dereference_variable *var_ref = (*rvalue)->as_dereference_variable();
156    if (var_ref && !var_ref->type->is_array()) {
157       ir_constant *constant = var_ref->constant_expression_value();
158       if (constant) {
159          *rvalue = constant;
160          this->progress = true;
161       }
162    }
163 }
164
165 void
166 ir_constant_propagation_visitor::constant_propagation(ir_rvalue **rvalue) {
167
168    if (this->in_assignee || !*rvalue)
169       return;
170
171    const glsl_type *type = (*rvalue)->type;
172    if (!type->is_scalar() && !type->is_vector())
173       return;
174
175    ir_swizzle *swiz = NULL;
176    ir_dereference_variable *deref = (*rvalue)->as_dereference_variable();
177    if (!deref) {
178       swiz = (*rvalue)->as_swizzle();
179       if (!swiz)
180          return;
181
182       deref = swiz->val->as_dereference_variable();
183       if (!deref)
184          return;
185    }
186
187    ir_constant_data data;
188    memset(&data, 0, sizeof(data));
189
190    for (unsigned int i = 0; i < type->components(); i++) {
191       int channel;
192       acp_entry *found = NULL;
193
194       if (swiz) {
195          switch (i) {
196          case 0: channel = swiz->mask.x; break;
197          case 1: channel = swiz->mask.y; break;
198          case 2: channel = swiz->mask.z; break;
199          case 3: channel = swiz->mask.w; break;
200          default: assert(!"shouldn't be reached"); channel = 0; break;
201          }
202       } else {
203          channel = i;
204       }
205
206       foreach_in_list(acp_entry, entry, this->acp) {
207          if (entry->var == deref->var && entry->write_mask & (1 << channel)) {
208             found = entry;
209             break;
210          }
211       }
212
213       if (!found)
214          return;
215
216       int rhs_channel = 0;
217       for (int j = 0; j < 4; j++) {
218          if (j == channel)
219             break;
220          if (found->initial_values & (1 << j))
221             rhs_channel++;
222       }
223
224       switch (type->base_type) {
225       case GLSL_TYPE_FLOAT:
226          data.f[i] = found->constant->value.f[rhs_channel];
227          break;
228       case GLSL_TYPE_DOUBLE:
229          data.d[i] = found->constant->value.d[rhs_channel];
230          break;
231       case GLSL_TYPE_INT:
232          data.i[i] = found->constant->value.i[rhs_channel];
233          break;
234       case GLSL_TYPE_UINT:
235          data.u[i] = found->constant->value.u[rhs_channel];
236          break;
237       case GLSL_TYPE_BOOL:
238          data.b[i] = found->constant->value.b[rhs_channel];
239          break;
240       case GLSL_TYPE_UINT64:
241          data.u64[i] = found->constant->value.u64[rhs_channel];
242          break;
243       case GLSL_TYPE_INT64:
244          data.i64[i] = found->constant->value.i64[rhs_channel];
245          break;
246       default:
247          assert(!"not reached");
248          break;
249       }
250    }
251
252    *rvalue = new(ralloc_parent(deref)) ir_constant(type, &data);
253    this->progress = true;
254 }
255
256 void
257 ir_constant_propagation_visitor::handle_rvalue(ir_rvalue **rvalue)
258 {
259    constant_propagation(rvalue);
260    constant_folding(rvalue);
261 }
262
263 ir_visitor_status
264 ir_constant_propagation_visitor::visit_enter(ir_function_signature *ir)
265 {
266    /* Treat entry into a function signature as a completely separate
267     * block.  Any instructions at global scope will be shuffled into
268     * main() at link time, so they're irrelevant to us.
269     */
270    exec_list *orig_acp = this->acp;
271    hash_table *orig_kills = this->kills;
272    bool orig_killed_all = this->killed_all;
273
274    this->acp = new(mem_ctx) exec_list;
275    this->kills = _mesa_hash_table_create(mem_ctx, _mesa_hash_pointer,
276                                          _mesa_key_pointer_equal);
277    this->killed_all = false;
278
279    visit_list_elements(this, &ir->body);
280
281    this->kills = orig_kills;
282    this->acp = orig_acp;
283    this->killed_all = orig_killed_all;
284
285    return visit_continue_with_parent;
286 }
287
288 ir_visitor_status
289 ir_constant_propagation_visitor::visit_leave(ir_assignment *ir)
290 {
291   constant_folding(&ir->rhs);
292
293    if (this->in_assignee)
294       return visit_continue;
295
296    unsigned kill_mask = ir->write_mask;
297    if (ir->lhs->as_dereference_array()) {
298       /* The LHS of the assignment uses an array indexing operator (e.g. v[i]
299        * = ...;).  Since we only try to constant propagate vectors and
300        * scalars, this means that either (a) array indexing is being used to
301        * select a vector component, or (b) the variable in question is neither
302        * a scalar or a vector, so we don't care about it.  In the former case,
303        * we want to kill the whole vector, since in general we can't predict
304        * which vector component will be selected by array indexing.  In the
305        * latter case, it doesn't matter what we do, so go ahead and kill the
306        * whole variable anyway.
307        *
308        * Note that if the array index is constant (e.g. v[2] = ...;), we could
309        * in principle be smarter, but we don't need to, because a future
310        * optimization pass will convert it to a simple assignment with the
311        * correct mask.
312        */
313       kill_mask = ~0;
314    }
315    kill(ir->lhs->variable_referenced(), kill_mask);
316
317    add_constant(ir);
318
319    return visit_continue;
320 }
321
322 ir_visitor_status
323 ir_constant_propagation_visitor::visit_enter(ir_function *ir)
324 {
325    (void) ir;
326    return visit_continue;
327 }
328
329 ir_visitor_status
330 ir_constant_propagation_visitor::visit_enter(ir_call *ir)
331 {
332    /* Do constant propagation on call parameters, but skip any out params */
333    foreach_two_lists(formal_node, &ir->callee->parameters,
334                      actual_node, &ir->actual_parameters) {
335       ir_variable *sig_param = (ir_variable *) formal_node;
336       ir_rvalue *param = (ir_rvalue *) actual_node;
337       if (sig_param->data.mode != ir_var_function_out
338           && sig_param->data.mode != ir_var_function_inout) {
339          ir_rvalue *new_param = param;
340          handle_rvalue(&new_param);
341          if (new_param != param)
342             param->replace_with(new_param);
343          else
344             param->accept(this);
345       }
346    }
347
348    /* Since we're unlinked, we don't (necssarily) know the side effects of
349     * this call.  So kill all copies.
350     */
351    acp->make_empty();
352    this->killed_all = true;
353
354    return visit_continue_with_parent;
355 }
356
357 void
358 ir_constant_propagation_visitor::handle_if_block(exec_list *instructions)
359 {
360    exec_list *orig_acp = this->acp;
361    hash_table *orig_kills = this->kills;
362    bool orig_killed_all = this->killed_all;
363
364    this->acp = new(mem_ctx) exec_list;
365    this->kills = _mesa_hash_table_create(mem_ctx, _mesa_hash_pointer,
366                                          _mesa_key_pointer_equal);
367    this->killed_all = false;
368
369    /* Populate the initial acp with a constant of the original */
370    foreach_in_list(acp_entry, a, orig_acp) {
371       this->acp->push_tail(new(this->lin_ctx) acp_entry(a));
372    }
373
374    visit_list_elements(this, instructions);
375
376    if (this->killed_all) {
377       orig_acp->make_empty();
378    }
379
380    hash_table *new_kills = this->kills;
381    this->kills = orig_kills;
382    this->acp = orig_acp;
383    this->killed_all = this->killed_all || orig_killed_all;
384
385    hash_entry *htk;
386    hash_table_foreach(new_kills, htk) {
387       kill_entry *k = (kill_entry *) htk->data;
388       kill(k->var, k->write_mask);
389    }
390 }
391
392 ir_visitor_status
393 ir_constant_propagation_visitor::visit_enter(ir_if *ir)
394 {
395    ir->condition->accept(this);
396    handle_rvalue(&ir->condition);
397
398    handle_if_block(&ir->then_instructions);
399    handle_if_block(&ir->else_instructions);
400
401    /* handle_if_block() already descended into the children. */
402    return visit_continue_with_parent;
403 }
404
405 ir_visitor_status
406 ir_constant_propagation_visitor::visit_enter(ir_loop *ir)
407 {
408    exec_list *orig_acp = this->acp;
409    hash_table *orig_kills = this->kills;
410    bool orig_killed_all = this->killed_all;
411
412    /* FINISHME: For now, the initial acp for loops is totally empty.
413     * We could go through once, then go through again with the acp
414     * cloned minus the killed entries after the first run through.
415     */
416    this->acp = new(mem_ctx) exec_list;
417    this->kills = _mesa_hash_table_create(mem_ctx, _mesa_hash_pointer,
418                                          _mesa_key_pointer_equal);
419    this->killed_all = false;
420
421    visit_list_elements(this, &ir->body_instructions);
422
423    if (this->killed_all) {
424       orig_acp->make_empty();
425    }
426
427    hash_table *new_kills = this->kills;
428    this->kills = orig_kills;
429    this->acp = orig_acp;
430    this->killed_all = this->killed_all || orig_killed_all;
431
432    hash_entry *htk;
433    hash_table_foreach(new_kills, htk) {
434       kill_entry *k = (kill_entry *) htk->data;
435       kill(k->var, k->write_mask);
436    }
437
438    /* already descended into the children. */
439    return visit_continue_with_parent;
440 }
441
442 void
443 ir_constant_propagation_visitor::kill(ir_variable *var, unsigned write_mask)
444 {
445    assert(var != NULL);
446
447    /* We don't track non-vectors. */
448    if (!var->type->is_vector() && !var->type->is_scalar())
449       return;
450
451    /* Remove any entries currently in the ACP for this kill. */
452    foreach_in_list_safe(acp_entry, entry, this->acp) {
453       if (entry->var == var) {
454          entry->write_mask &= ~write_mask;
455          if (entry->write_mask == 0)
456             entry->remove();
457       }
458    }
459
460    /* Add this writemask of the variable to the hash table of killed
461     * variables in this block.
462     */
463    hash_entry *kill_hash_entry = _mesa_hash_table_search(this->kills, var);
464    if (kill_hash_entry) {
465       kill_entry *entry = (kill_entry *) kill_hash_entry->data;
466       entry->write_mask |= write_mask;
467       return;
468    }
469    /* Not already in the hash table.  Make new entry. */
470    _mesa_hash_table_insert(this->kills, var,
471                            new(this->lin_ctx) kill_entry(var, write_mask));
472 }
473
474 /**
475  * Adds an entry to the available constant list if it's a plain assignment
476  * of a variable to a variable.
477  */
478 void
479 ir_constant_propagation_visitor::add_constant(ir_assignment *ir)
480 {
481    acp_entry *entry;
482
483    if (ir->condition)
484       return;
485
486    if (!ir->write_mask)
487       return;
488
489    ir_dereference_variable *deref = ir->lhs->as_dereference_variable();
490    ir_constant *constant = ir->rhs->as_constant();
491
492    if (!deref || !constant)
493       return;
494
495    /* Only do constant propagation on vectors.  Constant matrices,
496     * arrays, or structures would require more work elsewhere.
497     */
498    if (!deref->var->type->is_vector() && !deref->var->type->is_scalar())
499       return;
500
501    /* We can't do copy propagation on buffer variables, since the underlying
502     * memory storage is shared across multiple threads we can't be sure that
503     * the variable value isn't modified between this assignment and the next
504     * instruction where its value is read.
505     */
506    if (deref->var->data.mode == ir_var_shader_storage ||
507        deref->var->data.mode == ir_var_shader_shared)
508       return;
509
510    entry = new(this->lin_ctx) acp_entry(deref->var, ir->write_mask, constant);
511    this->acp->push_tail(entry);
512 }
513
514 } /* unnamed namespace */
515
516 /**
517  * Does a constant propagation pass on the code present in the instruction stream.
518  */
519 bool
520 do_constant_propagation(exec_list *instructions)
521 {
522    ir_constant_propagation_visitor v;
523
524    visit_list_elements(&v, instructions);
525
526    return v.progress;
527 }