Subversion Repositories Kolibri OS

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
4358 Serge 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 opt_constant_variable.cpp
26
 *
27
 * Marks variables assigned a single constant value over the course
28
 * of the program as constant.
29
 *
30
 * The goal here is to trigger further constant folding and then dead
31
 * code elimination.  This is common with vector/matrix constructors
32
 * and calls to builtin functions.
33
 */
34
 
35
#include "ir.h"
36
#include "ir_visitor.h"
37
#include "ir_optimization.h"
38
#include "glsl_types.h"
39
 
40
namespace {
41
 
42
struct assignment_entry {
43
   exec_node link;
44
   int assignment_count;
45
   ir_variable *var;
46
   ir_constant *constval;
47
   bool our_scope;
48
};
49
 
50
class ir_constant_variable_visitor : public ir_hierarchical_visitor {
51
public:
52
   virtual ir_visitor_status visit_enter(ir_dereference_variable *);
53
   virtual ir_visitor_status visit(ir_variable *);
54
   virtual ir_visitor_status visit_enter(ir_assignment *);
55
   virtual ir_visitor_status visit_enter(ir_call *);
56
 
57
   exec_list list;
58
};
59
 
60
} /* unnamed namespace */
61
 
62
static struct assignment_entry *
63
get_assignment_entry(ir_variable *var, exec_list *list)
64
{
65
   struct assignment_entry *entry;
66
 
67
   foreach_list_typed(struct assignment_entry, entry, link, list) {
68
      if (entry->var == var)
69
	 return entry;
70
   }
71
 
72
   entry = (struct assignment_entry *)calloc(1, sizeof(*entry));
73
   entry->var = var;
74
   list->push_head(&entry->link);
75
   return entry;
76
}
77
 
78
ir_visitor_status
79
ir_constant_variable_visitor::visit(ir_variable *ir)
80
{
81
   struct assignment_entry *entry = get_assignment_entry(ir, &this->list);
82
   entry->our_scope = true;
83
   return visit_continue;
84
}
85
 
86
/* Skip derefs of variables so that we can detect declarations. */
87
ir_visitor_status
88
ir_constant_variable_visitor::visit_enter(ir_dereference_variable *ir)
89
{
90
   (void)ir;
91
   return visit_continue_with_parent;
92
}
93
 
94
ir_visitor_status
95
ir_constant_variable_visitor::visit_enter(ir_assignment *ir)
96
{
97
   ir_constant *constval;
98
   struct assignment_entry *entry;
99
 
100
   entry = get_assignment_entry(ir->lhs->variable_referenced(), &this->list);
101
   assert(entry);
102
   entry->assignment_count++;
103
 
104
   /* If it's already constant, don't do the work. */
105
   if (entry->var->constant_value)
106
      return visit_continue;
107
 
108
   /* OK, now find if we actually have all the right conditions for
109
    * this to be a constant value assigned to the var.
110
    */
111
   if (ir->condition)
112
      return visit_continue;
113
 
114
   ir_variable *var = ir->whole_variable_written();
115
   if (!var)
116
      return visit_continue;
117
 
118
   constval = ir->rhs->constant_expression_value();
119
   if (!constval)
120
      return visit_continue;
121
 
122
   /* Mark this entry as having a constant assignment (if the
123
    * assignment count doesn't go >1).  do_constant_variable will fix
124
    * up the variable with the constant value later.
125
    */
126
   entry->constval = constval;
127
 
128
   return visit_continue;
129
}
130
 
131
ir_visitor_status
132
ir_constant_variable_visitor::visit_enter(ir_call *ir)
133
{
134
   /* Mark any out parameters as assigned to */
135
   exec_list_iterator sig_iter = ir->callee->parameters.iterator();
136
   foreach_iter(exec_list_iterator, iter, *ir) {
137
      ir_rvalue *param_rval = (ir_rvalue *)iter.get();
138
      ir_variable *param = (ir_variable *)sig_iter.get();
139
 
140
      if (param->mode == ir_var_function_out ||
141
	  param->mode == ir_var_function_inout) {
142
	 ir_variable *var = param_rval->variable_referenced();
143
	 struct assignment_entry *entry;
144
 
145
	 assert(var);
146
	 entry = get_assignment_entry(var, &this->list);
147
	 entry->assignment_count++;
148
      }
149
      sig_iter.next();
150
   }
151
 
152
   /* Mark the return storage as having been assigned to */
153
   if (ir->return_deref != NULL) {
154
      ir_variable *var = ir->return_deref->variable_referenced();
155
      struct assignment_entry *entry;
156
 
157
      assert(var);
158
      entry = get_assignment_entry(var, &this->list);
159
      entry->assignment_count++;
160
   }
161
 
162
   return visit_continue;
163
}
164
 
165
/**
166
 * Does a copy propagation pass on the code present in the instruction stream.
167
 */
168
bool
169
do_constant_variable(exec_list *instructions)
170
{
171
   bool progress = false;
172
   ir_constant_variable_visitor v;
173
 
174
   v.run(instructions);
175
 
176
   while (!v.list.is_empty()) {
177
 
178
      struct assignment_entry *entry;
179
      entry = exec_node_data(struct assignment_entry, v.list.head, link);
180
 
181
      if (entry->assignment_count == 1 && entry->constval && entry->our_scope) {
182
	 entry->var->constant_value = entry->constval;
183
	 progress = true;
184
      }
185
      entry->link.remove();
186
      free(entry);
187
   }
188
 
189
   return progress;
190
}
191
 
192
bool
193
do_constant_variable_unlinked(exec_list *instructions)
194
{
195
   bool progress = false;
196
 
197
   foreach_iter(exec_list_iterator, iter, *instructions) {
198
      ir_instruction *ir = (ir_instruction *)iter.get();
199
      ir_function *f = ir->as_function();
200
      if (f) {
201
	 foreach_iter(exec_list_iterator, sigiter, *f) {
202
	    ir_function_signature *sig =
203
	       (ir_function_signature *) sigiter.get();
204
	    if (do_constant_variable(&sig->body))
205
	       progress = true;
206
	 }
207
      }
208
   }
209
 
210
   return progress;
211
}