glsl2: Return a real progress value from constant folding.
[mesa.git] / src / glsl / ir_constant_folding.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_constant_folding.cpp
26 * Replace constant-valued expressions with references to constant values.
27 */
28
29 #include "ir.h"
30 #include "ir_visitor.h"
31 #include "ir_optimization.h"
32 #include "glsl_types.h"
33
34 /**
35 * Visitor class for replacing expressions with ir_constant values.
36 */
37
38 class ir_constant_folding_visitor : public ir_visitor {
39 public:
40 ir_constant_folding_visitor()
41 {
42 this->progress = false;
43 }
44
45 virtual ~ir_constant_folding_visitor()
46 {
47 /* empty */
48 }
49
50 /**
51 * \name Visit methods
52 *
53 * As typical for the visitor pattern, there must be one \c visit method for
54 * each concrete subclass of \c ir_instruction. Virtual base classes within
55 * the hierarchy should not have \c visit methods.
56 */
57 /*@{*/
58 virtual void visit(ir_variable *);
59 virtual void visit(ir_function_signature *);
60 virtual void visit(ir_function *);
61 virtual void visit(ir_expression *);
62 virtual void visit(ir_texture *);
63 virtual void visit(ir_swizzle *);
64 virtual void visit(ir_dereference_variable *);
65 virtual void visit(ir_dereference_array *);
66 virtual void visit(ir_dereference_record *);
67 virtual void visit(ir_assignment *);
68 virtual void visit(ir_constant *);
69 virtual void visit(ir_call *);
70 virtual void visit(ir_return *);
71 virtual void visit(ir_discard *);
72 virtual void visit(ir_if *);
73 virtual void visit(ir_loop *);
74 virtual void visit(ir_loop_jump *);
75 /*@}*/
76
77 void fold_constant(ir_rvalue **rvalue);
78
79 bool progress;
80 };
81
82 void
83 ir_constant_folding_visitor::fold_constant(ir_rvalue **rvalue)
84 {
85 if ((*rvalue)->ir_type == ir_type_constant)
86 return;
87
88 ir_constant *constant = (*rvalue)->constant_expression_value();
89 if (constant) {
90 *rvalue = constant;
91 this->progress = true;
92 } else {
93 (*rvalue)->accept(this);
94 }
95 }
96
97 void
98 ir_constant_folding_visitor::visit(ir_variable *ir)
99 {
100 (void) ir;
101 }
102
103
104 void
105 ir_constant_folding_visitor::visit(ir_function_signature *ir)
106 {
107 visit_exec_list(&ir->body, this);
108 }
109
110
111 void
112 ir_constant_folding_visitor::visit(ir_function *ir)
113 {
114 foreach_iter(exec_list_iterator, iter, *ir) {
115 ir_function_signature *const sig = (ir_function_signature *) iter.get();
116 sig->accept(this);
117 }
118 }
119
120 void
121 ir_constant_folding_visitor::visit(ir_expression *ir)
122 {
123 unsigned int operand;
124
125 for (operand = 0; operand < ir->get_num_operands(); operand++) {
126 fold_constant(&ir->operands[operand]);
127 }
128 }
129
130
131 void
132 ir_constant_folding_visitor::visit(ir_texture *ir)
133 {
134 // FINISHME: Do stuff with texture lookups
135 (void) ir;
136 }
137
138
139 void
140 ir_constant_folding_visitor::visit(ir_swizzle *ir)
141 {
142 ir->val->accept(this);
143 }
144
145
146 void
147 ir_constant_folding_visitor::visit(ir_dereference_variable *ir)
148 {
149 (void) ir;
150 }
151
152
153 void
154 ir_constant_folding_visitor::visit(ir_dereference_array *ir)
155 {
156 fold_constant(&ir->array_index);
157 ir->array->accept(this);
158 }
159
160
161 void
162 ir_constant_folding_visitor::visit(ir_dereference_record *ir)
163 {
164 ir->record->accept(this);
165 }
166
167
168 void
169 ir_constant_folding_visitor::visit(ir_assignment *ir)
170 {
171 fold_constant(&ir->rhs);
172
173 if (ir->condition) {
174 /* If the condition is constant, either remove the condition or
175 * remove the never-executed assignment.
176 */
177 ir_constant *const_val = ir->condition->constant_expression_value();
178 if (const_val) {
179 if (const_val->value.b[0])
180 ir->condition = NULL;
181 else
182 ir->remove();
183 }
184 this->progress = true;
185 }
186 }
187
188
189 void
190 ir_constant_folding_visitor::visit(ir_constant *ir)
191 {
192 (void) ir;
193 }
194
195
196 void
197 ir_constant_folding_visitor::visit(ir_call *ir)
198 {
199 (void) ir;
200 }
201
202
203 void
204 ir_constant_folding_visitor::visit(ir_return *ir)
205 {
206 (void) ir;
207 }
208
209
210 void
211 ir_constant_folding_visitor::visit(ir_discard *ir)
212 {
213 (void) ir;
214 }
215
216
217 void
218 ir_constant_folding_visitor::visit(ir_if *ir)
219 {
220 fold_constant(&ir->condition);
221
222 visit_exec_list(&ir->then_instructions, this);
223 visit_exec_list(&ir->else_instructions, this);
224 }
225
226
227 void
228 ir_constant_folding_visitor::visit(ir_loop *ir)
229 {
230 (void) ir;
231 }
232
233
234 void
235 ir_constant_folding_visitor::visit(ir_loop_jump *ir)
236 {
237 (void) ir;
238 }
239
240 bool
241 do_constant_folding(exec_list *instructions)
242 {
243 ir_constant_folding_visitor constant_folding;
244
245 visit_exec_list(instructions, &constant_folding);
246
247 return constant_folding.progress;
248 }