gtest: Update to 1.7.0.
[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 * 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_rvalue::accept(ir_hierarchical_visitor *v)
70 {
71 return v->visit(this);
72 }
73
74
75 ir_visitor_status
76 ir_variable::accept(ir_hierarchical_visitor *v)
77 {
78 return v->visit(this);
79 }
80
81
82 ir_visitor_status
83 ir_loop::accept(ir_hierarchical_visitor *v)
84 {
85 ir_visitor_status s = v->visit_enter(this);
86
87 if (s != visit_continue)
88 return (s == visit_continue_with_parent) ? visit_continue : s;
89
90 s = visit_list_elements(v, &this->body_instructions);
91 if (s == visit_stop)
92 return s;
93
94 return v->visit_leave(this);
95 }
96
97
98 ir_visitor_status
99 ir_loop_jump::accept(ir_hierarchical_visitor *v)
100 {
101 return v->visit(this);
102 }
103
104
105 ir_visitor_status
106 ir_function_signature::accept(ir_hierarchical_visitor *v)
107 {
108 ir_visitor_status s = v->visit_enter(this);
109 if (s != visit_continue)
110 return (s == visit_continue_with_parent) ? visit_continue : s;
111
112 s = visit_list_elements(v, &this->parameters);
113 if (s == visit_stop)
114 return s;
115
116 s = visit_list_elements(v, &this->body);
117 return (s == visit_stop) ? s : v->visit_leave(this);
118 }
119
120
121 ir_visitor_status
122 ir_function::accept(ir_hierarchical_visitor *v)
123 {
124 ir_visitor_status s = v->visit_enter(this);
125 if (s != visit_continue)
126 return (s == visit_continue_with_parent) ? visit_continue : s;
127
128 s = visit_list_elements(v, &this->signatures, false);
129 return (s == visit_stop) ? s : v->visit_leave(this);
130 }
131
132
133 ir_visitor_status
134 ir_expression::accept(ir_hierarchical_visitor *v)
135 {
136 ir_visitor_status s = v->visit_enter(this);
137
138 if (s != visit_continue)
139 return (s == visit_continue_with_parent) ? visit_continue : s;
140
141 for (unsigned i = 0; i < this->get_num_operands(); i++) {
142 switch (this->operands[i]->accept(v)) {
143 case visit_continue:
144 break;
145
146 case visit_continue_with_parent:
147 // I wish for Java's labeled break-statement here.
148 goto done;
149
150 case visit_stop:
151 return s;
152 }
153 }
154
155 done:
156 return v->visit_leave(this);
157 }
158
159 ir_visitor_status
160 ir_texture::accept(ir_hierarchical_visitor *v)
161 {
162 ir_visitor_status s = v->visit_enter(this);
163 if (s != visit_continue)
164 return (s == visit_continue_with_parent) ? visit_continue : s;
165
166 s = this->sampler->accept(v);
167 if (s != visit_continue)
168 return (s == visit_continue_with_parent) ? visit_continue : s;
169
170 if (this->coordinate) {
171 s = this->coordinate->accept(v);
172 if (s != visit_continue)
173 return (s == visit_continue_with_parent) ? visit_continue : s;
174 }
175
176 if (this->projector) {
177 s = this->projector->accept(v);
178 if (s != visit_continue)
179 return (s == visit_continue_with_parent) ? visit_continue : s;
180 }
181
182 if (this->shadow_comparitor) {
183 s = this->shadow_comparitor->accept(v);
184 if (s != visit_continue)
185 return (s == visit_continue_with_parent) ? visit_continue : s;
186 }
187
188 if (this->offset) {
189 s = this->offset->accept(v);
190 if (s != visit_continue)
191 return (s == visit_continue_with_parent) ? visit_continue : s;
192 }
193
194 switch (this->op) {
195 case ir_tex:
196 case ir_lod:
197 case ir_query_levels:
198 break;
199 case ir_txb:
200 s = this->lod_info.bias->accept(v);
201 if (s != visit_continue)
202 return (s == visit_continue_with_parent) ? visit_continue : s;
203 break;
204 case ir_txl:
205 case ir_txf:
206 case ir_txs:
207 s = this->lod_info.lod->accept(v);
208 if (s != visit_continue)
209 return (s == visit_continue_with_parent) ? visit_continue : s;
210 break;
211 case ir_txf_ms:
212 s = this->lod_info.sample_index->accept(v);
213 if (s != visit_continue)
214 return (s == visit_continue_with_parent) ? visit_continue : s;
215 break;
216 case ir_txd:
217 s = this->lod_info.grad.dPdx->accept(v);
218 if (s != visit_continue)
219 return (s == visit_continue_with_parent) ? visit_continue : s;
220
221 s = this->lod_info.grad.dPdy->accept(v);
222 if (s != visit_continue)
223 return (s == visit_continue_with_parent) ? visit_continue : s;
224 break;
225 case ir_tg4:
226 s = this->lod_info.component->accept(v);
227 if (s != visit_continue)
228 return (s == visit_continue_with_parent) ? visit_continue : s;
229 break;
230 }
231
232 return (s == visit_stop) ? s : v->visit_leave(this);
233 }
234
235
236 ir_visitor_status
237 ir_swizzle::accept(ir_hierarchical_visitor *v)
238 {
239 ir_visitor_status s = v->visit_enter(this);
240 if (s != visit_continue)
241 return (s == visit_continue_with_parent) ? visit_continue : s;
242
243 s = this->val->accept(v);
244 return (s == visit_stop) ? s : v->visit_leave(this);
245 }
246
247
248 ir_visitor_status
249 ir_dereference_variable::accept(ir_hierarchical_visitor *v)
250 {
251 return v->visit(this);
252 }
253
254
255 ir_visitor_status
256 ir_dereference_array::accept(ir_hierarchical_visitor *v)
257 {
258 ir_visitor_status s = v->visit_enter(this);
259 if (s != visit_continue)
260 return (s == visit_continue_with_parent) ? visit_continue : s;
261
262 /* The array index is not the target of the assignment, so clear the
263 * 'in_assignee' flag. Restore it after returning from the array index.
264 */
265 const bool was_in_assignee = v->in_assignee;
266 v->in_assignee = false;
267 s = this->array_index->accept(v);
268 v->in_assignee = was_in_assignee;
269
270 if (s != visit_continue)
271 return (s == visit_continue_with_parent) ? visit_continue : s;
272
273 s = this->array->accept(v);
274 return (s == visit_stop) ? s : v->visit_leave(this);
275 }
276
277
278 ir_visitor_status
279 ir_dereference_record::accept(ir_hierarchical_visitor *v)
280 {
281 ir_visitor_status s = v->visit_enter(this);
282 if (s != visit_continue)
283 return (s == visit_continue_with_parent) ? visit_continue : s;
284
285 s = this->record->accept(v);
286 return (s == visit_stop) ? s : v->visit_leave(this);
287 }
288
289
290 ir_visitor_status
291 ir_assignment::accept(ir_hierarchical_visitor *v)
292 {
293 ir_visitor_status s = v->visit_enter(this);
294 if (s != visit_continue)
295 return (s == visit_continue_with_parent) ? visit_continue : s;
296
297 v->in_assignee = true;
298 s = this->lhs->accept(v);
299 v->in_assignee = false;
300 if (s != visit_continue)
301 return (s == visit_continue_with_parent) ? visit_continue : s;
302
303 s = this->rhs->accept(v);
304 if (s != visit_continue)
305 return (s == visit_continue_with_parent) ? visit_continue : s;
306
307 if (this->condition)
308 s = this->condition->accept(v);
309
310 return (s == visit_stop) ? s : v->visit_leave(this);
311 }
312
313
314 ir_visitor_status
315 ir_constant::accept(ir_hierarchical_visitor *v)
316 {
317 return v->visit(this);
318 }
319
320
321 ir_visitor_status
322 ir_call::accept(ir_hierarchical_visitor *v)
323 {
324 ir_visitor_status s = v->visit_enter(this);
325 if (s != visit_continue)
326 return (s == visit_continue_with_parent) ? visit_continue : s;
327
328 if (this->return_deref != NULL) {
329 v->in_assignee = true;
330 s = this->return_deref->accept(v);
331 v->in_assignee = false;
332 if (s != visit_continue)
333 return (s == visit_continue_with_parent) ? visit_continue : s;
334 }
335
336 s = visit_list_elements(v, &this->actual_parameters, false);
337 if (s == visit_stop)
338 return s;
339
340 return v->visit_leave(this);
341 }
342
343
344 ir_visitor_status
345 ir_return::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 ir_rvalue *val = this->get_value();
352 if (val) {
353 s = val->accept(v);
354 if (s != visit_continue)
355 return (s == visit_continue_with_parent) ? visit_continue : s;
356 }
357
358 return v->visit_leave(this);
359 }
360
361
362 ir_visitor_status
363 ir_discard::accept(ir_hierarchical_visitor *v)
364 {
365 ir_visitor_status s = v->visit_enter(this);
366 if (s != visit_continue)
367 return (s == visit_continue_with_parent) ? visit_continue : s;
368
369 if (this->condition != NULL) {
370 s = this->condition->accept(v);
371 if (s != visit_continue)
372 return (s == visit_continue_with_parent) ? visit_continue : s;
373 }
374
375 return v->visit_leave(this);
376 }
377
378
379 ir_visitor_status
380 ir_if::accept(ir_hierarchical_visitor *v)
381 {
382 ir_visitor_status s = v->visit_enter(this);
383 if (s != visit_continue)
384 return (s == visit_continue_with_parent) ? visit_continue : s;
385
386 s = this->condition->accept(v);
387 if (s != visit_continue)
388 return (s == visit_continue_with_parent) ? visit_continue : s;
389
390 if (s != visit_continue_with_parent) {
391 s = visit_list_elements(v, &this->then_instructions);
392 if (s == visit_stop)
393 return s;
394 }
395
396 if (s != visit_continue_with_parent) {
397 s = visit_list_elements(v, &this->else_instructions);
398 if (s == visit_stop)
399 return s;
400 }
401
402 return v->visit_leave(this);
403 }
404
405 ir_visitor_status
406 ir_emit_vertex::accept(ir_hierarchical_visitor *v)
407 {
408 return v->visit(this);
409 }
410
411
412 ir_visitor_status
413 ir_end_primitive::accept(ir_hierarchical_visitor *v)
414 {
415 return v->visit(this);
416 }