glsl2: Add a pass to convert mod(a, b) to b * fract(a/b).
[mesa.git] / src / glsl / ir_hv_accept.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 #include "ir.h"
25
26 /**
27 * \file ir_hv_accept.cpp
28 * Implementations of all hierarchical visitor accept methods for IR
29 * instructions.
30 */
31
32 /**
33 * Process a list of nodes using a hierarchical vistor
34 *
35 * \warning
36 * This function will operate correctly if a node being processed is removed
37 * from list. However, if nodes are added to the list after the node being
38 * processed, some of the added noded may not be processed.
39 */
40 ir_visitor_status
41 visit_list_elements(ir_hierarchical_visitor *v, exec_list *l)
42 {
43 exec_node *next;
44 ir_instruction *prev_base_ir = v->base_ir;
45
46 for (exec_node *n = l->head; n->next != NULL; n = next) {
47 next = n->next;
48
49 ir_instruction *const ir = (ir_instruction *) n;
50 v->base_ir = ir;
51 ir_visitor_status s = ir->accept(v);
52
53 if (s != visit_continue)
54 return s;
55 }
56 v->base_ir = prev_base_ir;
57
58 return visit_continue;
59 }
60
61
62 ir_visitor_status
63 ir_variable::accept(ir_hierarchical_visitor *v)
64 {
65 return v->visit(this);
66 }
67
68
69 ir_visitor_status
70 ir_loop::accept(ir_hierarchical_visitor *v)
71 {
72 ir_visitor_status s = v->visit_enter(this);
73
74 if (s != visit_continue)
75 return (s == visit_continue_with_parent) ? visit_continue : s;
76
77 s = visit_list_elements(v, &this->body_instructions);
78 if (s == visit_stop)
79 return s;
80
81 if (s != visit_continue_with_parent) {
82 if (this->from) {
83 s = this->from->accept(v);
84 if (s != visit_continue)
85 return (s == visit_continue_with_parent) ? visit_continue : s;
86 }
87
88 if (this->to) {
89 s = this->to->accept(v);
90 if (s != visit_continue)
91 return (s == visit_continue_with_parent) ? visit_continue : s;
92 }
93
94 if (this->increment) {
95 s = this->increment->accept(v);
96 if (s != visit_continue)
97 return (s == visit_continue_with_parent) ? visit_continue : s;
98 }
99 }
100
101 return v->visit_leave(this);
102 }
103
104
105 ir_visitor_status
106 ir_loop_jump::accept(ir_hierarchical_visitor *v)
107 {
108 return v->visit(this);
109 }
110
111
112 ir_visitor_status
113 ir_function_signature::accept(ir_hierarchical_visitor *v)
114 {
115 ir_visitor_status s = v->visit_enter(this);
116 if (s != visit_continue)
117 return (s == visit_continue_with_parent) ? visit_continue : s;
118
119 s = visit_list_elements(v, &this->body);
120 return (s == visit_stop) ? s : v->visit_leave(this);
121 }
122
123
124 ir_visitor_status
125 ir_function::accept(ir_hierarchical_visitor *v)
126 {
127 ir_visitor_status s = v->visit_enter(this);
128 if (s != visit_continue)
129 return (s == visit_continue_with_parent) ? visit_continue : s;
130
131 s = visit_list_elements(v, &this->signatures);
132 return (s == visit_stop) ? s : v->visit_leave(this);
133 }
134
135
136 ir_visitor_status
137 ir_expression::accept(ir_hierarchical_visitor *v)
138 {
139 ir_visitor_status s = v->visit_enter(this);
140
141 if (s != visit_continue)
142 return (s == visit_continue_with_parent) ? visit_continue : s;
143
144 for (unsigned i = 0; i < this->get_num_operands(); i++) {
145 switch (this->operands[i]->accept(v)) {
146 case visit_continue:
147 break;
148
149 case visit_continue_with_parent:
150 // I wish for Java's labeled break-statement here.
151 goto done;
152
153 case visit_stop:
154 return s;
155 }
156 }
157
158 done:
159 return v->visit_leave(this);
160 }
161
162 ir_visitor_status
163 ir_texture::accept(ir_hierarchical_visitor *v)
164 {
165 ir_visitor_status s = v->visit_enter(this);
166 if (s != visit_continue)
167 return (s == visit_continue_with_parent) ? visit_continue : s;
168
169 s = this->sampler->accept(v);
170 if (s != visit_continue)
171 return (s == visit_continue_with_parent) ? visit_continue : s;
172
173 s = this->coordinate->accept(v);
174 if (s != visit_continue)
175 return (s == visit_continue_with_parent) ? visit_continue : s;
176
177 if (this->projector) {
178 s = this->projector->accept(v);
179 if (s != visit_continue)
180 return (s == visit_continue_with_parent) ? visit_continue : s;
181 }
182
183 if (this->shadow_comparitor) {
184 s = this->shadow_comparitor->accept(v);
185 if (s != visit_continue)
186 return (s == visit_continue_with_parent) ? visit_continue : s;
187 }
188
189 switch (this->op) {
190 case ir_tex:
191 break;
192 case ir_txb:
193 s = this->lod_info.bias->accept(v);
194 if (s != visit_continue)
195 return (s == visit_continue_with_parent) ? visit_continue : s;
196 break;
197 case ir_txl:
198 case ir_txf:
199 s = this->lod_info.lod->accept(v);
200 if (s != visit_continue)
201 return (s == visit_continue_with_parent) ? visit_continue : s;
202 break;
203 case ir_txd:
204 s = this->lod_info.grad.dPdx->accept(v);
205 if (s != visit_continue)
206 return (s == visit_continue_with_parent) ? visit_continue : s;
207
208 s = this->lod_info.grad.dPdy->accept(v);
209 if (s != visit_continue)
210 return (s == visit_continue_with_parent) ? visit_continue : s;
211 break;
212 }
213
214 return visit_continue_with_parent;
215 }
216
217
218 ir_visitor_status
219 ir_swizzle::accept(ir_hierarchical_visitor *v)
220 {
221 ir_visitor_status s = v->visit_enter(this);
222 if (s != visit_continue)
223 return (s == visit_continue_with_parent) ? visit_continue : s;
224
225 s = this->val->accept(v);
226 return (s == visit_stop) ? s : v->visit_leave(this);
227 }
228
229
230 ir_visitor_status
231 ir_dereference_variable::accept(ir_hierarchical_visitor *v)
232 {
233 return v->visit(this);
234 }
235
236
237 ir_visitor_status
238 ir_dereference_array::accept(ir_hierarchical_visitor *v)
239 {
240 ir_visitor_status s = v->visit_enter(this);
241 if (s != visit_continue)
242 return (s == visit_continue_with_parent) ? visit_continue : s;
243
244 s = this->array_index->accept(v);
245 if (s != visit_continue)
246 return (s == visit_continue_with_parent) ? visit_continue : s;
247
248 s = this->array->accept(v);
249 return (s == visit_stop) ? s : v->visit_leave(this);
250 }
251
252
253 ir_visitor_status
254 ir_dereference_record::accept(ir_hierarchical_visitor *v)
255 {
256 ir_visitor_status s = v->visit_enter(this);
257 if (s != visit_continue)
258 return (s == visit_continue_with_parent) ? visit_continue : s;
259
260 s = this->record->accept(v);
261 return (s == visit_stop) ? s : v->visit_leave(this);
262 }
263
264
265 ir_visitor_status
266 ir_assignment::accept(ir_hierarchical_visitor *v)
267 {
268 ir_visitor_status s = v->visit_enter(this);
269 if (s != visit_continue)
270 return (s == visit_continue_with_parent) ? visit_continue : s;
271
272 s = this->lhs->accept(v);
273 if (s != visit_continue)
274 return (s == visit_continue_with_parent) ? visit_continue : s;
275
276 s = this->rhs->accept(v);
277 if (s != visit_continue)
278 return (s == visit_continue_with_parent) ? visit_continue : s;
279
280 if (this->condition)
281 s = this->condition->accept(v);
282
283 return (s == visit_stop) ? s : v->visit_leave(this);
284 }
285
286
287 ir_visitor_status
288 ir_constant::accept(ir_hierarchical_visitor *v)
289 {
290 return v->visit(this);
291 }
292
293
294 ir_visitor_status
295 ir_call::accept(ir_hierarchical_visitor *v)
296 {
297 ir_visitor_status s = v->visit_enter(this);
298 if (s != visit_continue)
299 return (s == visit_continue_with_parent) ? visit_continue : s;
300
301 s = visit_list_elements(v, &this->actual_parameters);
302 if (s == visit_stop)
303 return s;
304
305 return v->visit_leave(this);
306 }
307
308
309 ir_visitor_status
310 ir_return::accept(ir_hierarchical_visitor *v)
311 {
312 ir_visitor_status s = v->visit_enter(this);
313 if (s != visit_continue)
314 return (s == visit_continue_with_parent) ? visit_continue : s;
315
316 ir_rvalue *val = this->get_value();
317 if (val) {
318 s = val->accept(v);
319 if (s != visit_continue)
320 return (s == visit_continue_with_parent) ? visit_continue : s;
321 }
322
323 return v->visit_leave(this);
324 }
325
326
327 ir_visitor_status
328 ir_discard::accept(ir_hierarchical_visitor *v)
329 {
330 ir_visitor_status s = v->visit_enter(this);
331 if (s != visit_continue)
332 return (s == visit_continue_with_parent) ? visit_continue : s;
333
334 if (this->condition != NULL) {
335 s = this->condition->accept(v);
336 if (s != visit_continue)
337 return (s == visit_continue_with_parent) ? visit_continue : s;
338 }
339
340 return v->visit_leave(this);
341 }
342
343
344 ir_visitor_status
345 ir_if::accept(ir_hierarchical_visitor *v)
346 {
347 ir_visitor_status s = v->visit_enter(this);
348 if (s != visit_continue)
349 return (s == visit_continue_with_parent) ? visit_continue : s;
350
351 s = this->condition->accept(v);
352 if (s != visit_continue)
353 return (s == visit_continue_with_parent) ? visit_continue : s;
354
355 if (s != visit_continue_with_parent) {
356 s = visit_list_elements(v, &this->then_instructions);
357 if (s == visit_stop)
358 return s;
359 }
360
361 if (s != visit_continue_with_parent) {
362 s = visit_list_elements(v, &this->else_instructions);
363 if (s == visit_stop)
364 return s;
365 }
366
367 return v->visit_leave(this);
368 }