glsl2: Don't forget to walk the parameters to a function in the hv.
[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->parameters);
120 if (s == visit_stop)
121 return s;
122
123 s = visit_list_elements(v, &this->body);
124 return (s == visit_stop) ? s : v->visit_leave(this);
125 }
126
127
128 ir_visitor_status
129 ir_function::accept(ir_hierarchical_visitor *v)
130 {
131 ir_visitor_status s = v->visit_enter(this);
132 if (s != visit_continue)
133 return (s == visit_continue_with_parent) ? visit_continue : s;
134
135 s = visit_list_elements(v, &this->signatures);
136 return (s == visit_stop) ? s : v->visit_leave(this);
137 }
138
139
140 ir_visitor_status
141 ir_expression::accept(ir_hierarchical_visitor *v)
142 {
143 ir_visitor_status s = v->visit_enter(this);
144
145 if (s != visit_continue)
146 return (s == visit_continue_with_parent) ? visit_continue : s;
147
148 for (unsigned i = 0; i < this->get_num_operands(); i++) {
149 switch (this->operands[i]->accept(v)) {
150 case visit_continue:
151 break;
152
153 case visit_continue_with_parent:
154 // I wish for Java's labeled break-statement here.
155 goto done;
156
157 case visit_stop:
158 return s;
159 }
160 }
161
162 done:
163 return v->visit_leave(this);
164 }
165
166 ir_visitor_status
167 ir_texture::accept(ir_hierarchical_visitor *v)
168 {
169 ir_visitor_status s = v->visit_enter(this);
170 if (s != visit_continue)
171 return (s == visit_continue_with_parent) ? visit_continue : s;
172
173 s = this->sampler->accept(v);
174 if (s != visit_continue)
175 return (s == visit_continue_with_parent) ? visit_continue : s;
176
177 s = this->coordinate->accept(v);
178 if (s != visit_continue)
179 return (s == visit_continue_with_parent) ? visit_continue : s;
180
181 if (this->projector) {
182 s = this->projector->accept(v);
183 if (s != visit_continue)
184 return (s == visit_continue_with_parent) ? visit_continue : s;
185 }
186
187 if (this->shadow_comparitor) {
188 s = this->shadow_comparitor->accept(v);
189 if (s != visit_continue)
190 return (s == visit_continue_with_parent) ? visit_continue : s;
191 }
192
193 switch (this->op) {
194 case ir_tex:
195 break;
196 case ir_txb:
197 s = this->lod_info.bias->accept(v);
198 if (s != visit_continue)
199 return (s == visit_continue_with_parent) ? visit_continue : s;
200 break;
201 case ir_txl:
202 case ir_txf:
203 s = this->lod_info.lod->accept(v);
204 if (s != visit_continue)
205 return (s == visit_continue_with_parent) ? visit_continue : s;
206 break;
207 case ir_txd:
208 s = this->lod_info.grad.dPdx->accept(v);
209 if (s != visit_continue)
210 return (s == visit_continue_with_parent) ? visit_continue : s;
211
212 s = this->lod_info.grad.dPdy->accept(v);
213 if (s != visit_continue)
214 return (s == visit_continue_with_parent) ? visit_continue : s;
215 break;
216 }
217
218 return visit_continue_with_parent;
219 }
220
221
222 ir_visitor_status
223 ir_swizzle::accept(ir_hierarchical_visitor *v)
224 {
225 ir_visitor_status s = v->visit_enter(this);
226 if (s != visit_continue)
227 return (s == visit_continue_with_parent) ? visit_continue : s;
228
229 s = this->val->accept(v);
230 return (s == visit_stop) ? s : v->visit_leave(this);
231 }
232
233
234 ir_visitor_status
235 ir_dereference_variable::accept(ir_hierarchical_visitor *v)
236 {
237 return v->visit(this);
238 }
239
240
241 ir_visitor_status
242 ir_dereference_array::accept(ir_hierarchical_visitor *v)
243 {
244 ir_visitor_status s = v->visit_enter(this);
245 if (s != visit_continue)
246 return (s == visit_continue_with_parent) ? visit_continue : s;
247
248 s = this->array_index->accept(v);
249 if (s != visit_continue)
250 return (s == visit_continue_with_parent) ? visit_continue : s;
251
252 s = this->array->accept(v);
253 return (s == visit_stop) ? s : v->visit_leave(this);
254 }
255
256
257 ir_visitor_status
258 ir_dereference_record::accept(ir_hierarchical_visitor *v)
259 {
260 ir_visitor_status s = v->visit_enter(this);
261 if (s != visit_continue)
262 return (s == visit_continue_with_parent) ? visit_continue : s;
263
264 s = this->record->accept(v);
265 return (s == visit_stop) ? s : v->visit_leave(this);
266 }
267
268
269 ir_visitor_status
270 ir_assignment::accept(ir_hierarchical_visitor *v)
271 {
272 ir_visitor_status s = v->visit_enter(this);
273 if (s != visit_continue)
274 return (s == visit_continue_with_parent) ? visit_continue : s;
275
276 s = this->lhs->accept(v);
277 if (s != visit_continue)
278 return (s == visit_continue_with_parent) ? visit_continue : s;
279
280 s = this->rhs->accept(v);
281 if (s != visit_continue)
282 return (s == visit_continue_with_parent) ? visit_continue : s;
283
284 if (this->condition)
285 s = this->condition->accept(v);
286
287 return (s == visit_stop) ? s : v->visit_leave(this);
288 }
289
290
291 ir_visitor_status
292 ir_constant::accept(ir_hierarchical_visitor *v)
293 {
294 return v->visit(this);
295 }
296
297
298 ir_visitor_status
299 ir_call::accept(ir_hierarchical_visitor *v)
300 {
301 ir_visitor_status s = v->visit_enter(this);
302 if (s != visit_continue)
303 return (s == visit_continue_with_parent) ? visit_continue : s;
304
305 s = visit_list_elements(v, &this->actual_parameters);
306 if (s == visit_stop)
307 return s;
308
309 return v->visit_leave(this);
310 }
311
312
313 ir_visitor_status
314 ir_return::accept(ir_hierarchical_visitor *v)
315 {
316 ir_visitor_status s = v->visit_enter(this);
317 if (s != visit_continue)
318 return (s == visit_continue_with_parent) ? visit_continue : s;
319
320 ir_rvalue *val = this->get_value();
321 if (val) {
322 s = val->accept(v);
323 if (s != visit_continue)
324 return (s == visit_continue_with_parent) ? visit_continue : s;
325 }
326
327 return v->visit_leave(this);
328 }
329
330
331 ir_visitor_status
332 ir_discard::accept(ir_hierarchical_visitor *v)
333 {
334 ir_visitor_status s = v->visit_enter(this);
335 if (s != visit_continue)
336 return (s == visit_continue_with_parent) ? visit_continue : s;
337
338 if (this->condition != NULL) {
339 s = this->condition->accept(v);
340 if (s != visit_continue)
341 return (s == visit_continue_with_parent) ? visit_continue : s;
342 }
343
344 return v->visit_leave(this);
345 }
346
347
348 ir_visitor_status
349 ir_if::accept(ir_hierarchical_visitor *v)
350 {
351 ir_visitor_status s = v->visit_enter(this);
352 if (s != visit_continue)
353 return (s == visit_continue_with_parent) ? visit_continue : s;
354
355 s = this->condition->accept(v);
356 if (s != visit_continue)
357 return (s == visit_continue_with_parent) ? visit_continue : s;
358
359 if (s != visit_continue_with_parent) {
360 s = visit_list_elements(v, &this->then_instructions);
361 if (s == visit_stop)
362 return s;
363 }
364
365 if (s != visit_continue_with_parent) {
366 s = visit_list_elements(v, &this->else_instructions);
367 if (s == visit_stop)
368 return s;
369 }
370
371 return v->visit_leave(this);
372 }