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