Tizen 2.0 Release
[profile/ivi/osmesa.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  * If statement_list is true (the default), this is a list of statements, so
36  * v->base_ir will be set to point to each statement just before iterating
37  * over it, and restored after iteration is complete.  If statement_list is
38  * false, this is a list that appears inside a statement (e.g. a parameter
39  * list), so v->base_ir will be left alone.
40  *
41  * \warning
42  * This function will operate correctly if a node being processed is removed
43  * from the list.  However, if nodes are added to the list after the node being
44  * processed, some of the added nodes may not be processed.
45  */
46 ir_visitor_status
47 visit_list_elements(ir_hierarchical_visitor *v, exec_list *l,
48                     bool statement_list)
49 {
50    ir_instruction *prev_base_ir = v->base_ir;
51
52    foreach_list_safe(n, l) {
53       ir_instruction *const ir = (ir_instruction *) n;
54       if (statement_list)
55          v->base_ir = ir;
56       ir_visitor_status s = ir->accept(v);
57
58       if (s != visit_continue)
59          return s;
60    }
61    if (statement_list)
62       v->base_ir = prev_base_ir;
63
64    return visit_continue;
65 }
66
67
68 ir_visitor_status
69 ir_variable::accept(ir_hierarchical_visitor *v)
70 {
71    return v->visit(this);
72 }
73
74
75 ir_visitor_status
76 ir_loop::accept(ir_hierarchical_visitor *v)
77 {
78    ir_visitor_status s = v->visit_enter(this);
79
80    if (s != visit_continue)
81       return (s == visit_continue_with_parent) ? visit_continue : s;
82
83    s = visit_list_elements(v, &this->body_instructions);
84    if (s == visit_stop)
85       return s;
86
87    if (s != visit_continue_with_parent) {
88       if (this->from) {
89          s = this->from->accept(v);
90          if (s != visit_continue)
91             return (s == visit_continue_with_parent) ? visit_continue : s;
92       }
93
94       if (this->to) {
95          s = this->to->accept(v);
96          if (s != visit_continue)
97             return (s == visit_continue_with_parent) ? visit_continue : s;
98       }
99
100       if (this->increment) {
101          s = this->increment->accept(v);
102          if (s != visit_continue)
103             return (s == visit_continue_with_parent) ? visit_continue : s;
104       }
105    }
106
107    return v->visit_leave(this);
108 }
109
110
111 ir_visitor_status
112 ir_loop_jump::accept(ir_hierarchical_visitor *v)
113 {
114    return v->visit(this);
115 }
116
117
118 ir_visitor_status
119 ir_function_signature::accept(ir_hierarchical_visitor *v)
120 {
121    ir_visitor_status s = v->visit_enter(this);
122    if (s != visit_continue)
123       return (s == visit_continue_with_parent) ? visit_continue : s;
124
125    s = visit_list_elements(v, &this->parameters);
126    if (s == visit_stop)
127       return s;
128
129    s = visit_list_elements(v, &this->body);
130    return (s == visit_stop) ? s : v->visit_leave(this);
131 }
132
133
134 ir_visitor_status
135 ir_function::accept(ir_hierarchical_visitor *v)
136 {
137    ir_visitor_status s = v->visit_enter(this);
138    if (s != visit_continue)
139       return (s == visit_continue_with_parent) ? visit_continue : s;
140
141    s = visit_list_elements(v, &this->signatures, false);
142    return (s == visit_stop) ? s : v->visit_leave(this);
143 }
144
145
146 ir_visitor_status
147 ir_expression::accept(ir_hierarchical_visitor *v)
148 {
149    ir_visitor_status s = v->visit_enter(this);
150
151    if (s != visit_continue)
152       return (s == visit_continue_with_parent) ? visit_continue : s;
153
154    for (unsigned i = 0; i < this->get_num_operands(); i++) {
155       switch (this->operands[i]->accept(v)) {
156       case visit_continue:
157          break;
158
159       case visit_continue_with_parent:
160          // I wish for Java's labeled break-statement here.
161          goto done;
162
163       case visit_stop:
164          return s;
165       }
166    }
167
168 done:
169    return v->visit_leave(this);
170 }
171
172 ir_visitor_status
173 ir_texture::accept(ir_hierarchical_visitor *v)
174 {
175    ir_visitor_status s = v->visit_enter(this);
176    if (s != visit_continue)
177       return (s == visit_continue_with_parent) ? visit_continue : s;
178
179    s = this->sampler->accept(v);
180    if (s != visit_continue)
181       return (s == visit_continue_with_parent) ? visit_continue : s;
182
183    s = this->coordinate->accept(v);
184    if (s != visit_continue)
185       return (s == visit_continue_with_parent) ? visit_continue : s;
186
187    if (this->projector) {
188       s = this->projector->accept(v);
189       if (s != visit_continue)
190          return (s == visit_continue_with_parent) ? visit_continue : s;
191    }
192
193    if (this->shadow_comparitor) {
194       s = this->shadow_comparitor->accept(v);
195       if (s != visit_continue)
196          return (s == visit_continue_with_parent) ? visit_continue : s;
197    }
198
199    if (this->offset) {
200       s = this->offset->accept(v);
201       if (s != visit_continue)
202          return (s == visit_continue_with_parent) ? visit_continue : s;
203    }
204
205    switch (this->op) {
206    case ir_tex:
207       break;
208    case ir_txb:
209       s = this->lod_info.bias->accept(v);
210       if (s != visit_continue)
211          return (s == visit_continue_with_parent) ? visit_continue : s;
212       break;
213    case ir_txl:
214    case ir_txf:
215       s = this->lod_info.lod->accept(v);
216       if (s != visit_continue)
217          return (s == visit_continue_with_parent) ? visit_continue : s;
218       break;
219    case ir_txd:
220       s = this->lod_info.grad.dPdx->accept(v);
221       if (s != visit_continue)
222          return (s == visit_continue_with_parent) ? visit_continue : s;
223
224       s = this->lod_info.grad.dPdy->accept(v);
225       if (s != visit_continue)
226          return (s == visit_continue_with_parent) ? visit_continue : s;
227       break;
228    }
229
230    return (s == visit_stop) ? s : v->visit_leave(this);
231 }
232
233
234 ir_visitor_status
235 ir_swizzle::accept(ir_hierarchical_visitor *v)
236 {
237    ir_visitor_status s = v->visit_enter(this);
238    if (s != visit_continue)
239       return (s == visit_continue_with_parent) ? visit_continue : s;
240
241    s = this->val->accept(v);
242    return (s == visit_stop) ? s : v->visit_leave(this);
243 }
244
245
246 ir_visitor_status
247 ir_dereference_variable::accept(ir_hierarchical_visitor *v)
248 {
249    return v->visit(this);
250 }
251
252
253 ir_visitor_status
254 ir_dereference_array::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    /* The array index is not the target of the assignment, so clear the
261     * 'in_assignee' flag.  Restore it after returning from the array index.
262     */
263    const bool was_in_assignee = v->in_assignee;
264    v->in_assignee = false;
265    s = this->array_index->accept(v);
266    v->in_assignee = was_in_assignee;
267
268    if (s != visit_continue)
269       return (s == visit_continue_with_parent) ? visit_continue : s;
270
271    s = this->array->accept(v);
272    return (s == visit_stop) ? s : v->visit_leave(this);
273 }
274
275
276 ir_visitor_status
277 ir_dereference_record::accept(ir_hierarchical_visitor *v)
278 {
279    ir_visitor_status s = v->visit_enter(this);
280    if (s != visit_continue)
281       return (s == visit_continue_with_parent) ? visit_continue : s;
282
283    s = this->record->accept(v);
284    return (s == visit_stop) ? s : v->visit_leave(this);
285 }
286
287
288 ir_visitor_status
289 ir_assignment::accept(ir_hierarchical_visitor *v)
290 {
291    ir_visitor_status s = v->visit_enter(this);
292    if (s != visit_continue)
293       return (s == visit_continue_with_parent) ? visit_continue : s;
294
295    v->in_assignee = true;
296    s = this->lhs->accept(v);
297    v->in_assignee = false;
298    if (s != visit_continue)
299       return (s == visit_continue_with_parent) ? visit_continue : s;
300
301    s = this->rhs->accept(v);
302    if (s != visit_continue)
303       return (s == visit_continue_with_parent) ? visit_continue : s;
304
305    if (this->condition)
306       s = this->condition->accept(v);
307
308    return (s == visit_stop) ? s : v->visit_leave(this);
309 }
310
311
312 ir_visitor_status
313 ir_constant::accept(ir_hierarchical_visitor *v)
314 {
315    return v->visit(this);
316 }
317
318
319 ir_visitor_status
320 ir_call::accept(ir_hierarchical_visitor *v)
321 {
322    ir_visitor_status s = v->visit_enter(this);
323    if (s != visit_continue)
324       return (s == visit_continue_with_parent) ? visit_continue : s;
325
326    s = visit_list_elements(v, &this->actual_parameters, false);
327    if (s == visit_stop)
328       return s;
329
330    return v->visit_leave(this);
331 }
332
333
334 ir_visitor_status
335 ir_return::accept(ir_hierarchical_visitor *v)
336 {
337    ir_visitor_status s = v->visit_enter(this);
338    if (s != visit_continue)
339       return (s == visit_continue_with_parent) ? visit_continue : s;
340
341    ir_rvalue *val = this->get_value();
342    if (val) {
343       s = val->accept(v);
344       if (s != visit_continue)
345          return (s == visit_continue_with_parent) ? visit_continue : s;
346    }
347
348    return v->visit_leave(this);
349 }
350
351
352 ir_visitor_status
353 ir_discard::accept(ir_hierarchical_visitor *v)
354 {
355    ir_visitor_status s = v->visit_enter(this);
356    if (s != visit_continue)
357       return (s == visit_continue_with_parent) ? visit_continue : s;
358
359    if (this->condition != NULL) {
360       s = this->condition->accept(v);
361       if (s != visit_continue)
362          return (s == visit_continue_with_parent) ? visit_continue : s;
363    }
364
365    return v->visit_leave(this);
366 }
367
368
369 ir_visitor_status
370 ir_if::accept(ir_hierarchical_visitor *v)
371 {
372    ir_visitor_status s = v->visit_enter(this);
373    if (s != visit_continue)
374       return (s == visit_continue_with_parent) ? visit_continue : s;
375
376    s = this->condition->accept(v);
377    if (s != visit_continue)
378       return (s == visit_continue_with_parent) ? visit_continue : s;
379
380    if (s != visit_continue_with_parent) {
381       s = visit_list_elements(v, &this->then_instructions);
382       if (s == visit_stop)
383          return s;
384    }
385
386    if (s != visit_continue_with_parent) {
387       s = visit_list_elements(v, &this->else_instructions);
388       if (s == visit_stop)
389          return s;
390    }
391
392    return v->visit_leave(this);
393 }