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 */ 46ir_visitor_status 47visit_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 67ir_visitor_status 68ir_rvalue::accept(ir_hierarchical_visitor *v) 69{ 70 return v->visit(this); 71} 72 73 74ir_visitor_status 75ir_variable::accept(ir_hierarchical_visitor *v) 76{ 77 return v->visit(this); 78} 79 80 81ir_visitor_status 82ir_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 97ir_visitor_status 98ir_loop_jump::accept(ir_hierarchical_visitor *v) 99{ 100 return v->visit(this); 101} 102 103 104ir_visitor_status 105ir_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 120ir_visitor_status 121ir_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 132ir_visitor_status 133ir_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 154done: 155 return v->visit_leave(this); 156} 157 158ir_visitor_status 159ir_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 244ir_visitor_status 245ir_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 256ir_visitor_status 257ir_dereference_variable::accept(ir_hierarchical_visitor *v) 258{ 259 return v->visit(this); 260} 261 262 263ir_visitor_status 264ir_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 286ir_visitor_status 287ir_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 298ir_visitor_status 299ir_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 319ir_visitor_status 320ir_constant::accept(ir_hierarchical_visitor *v) 321{ 322 return v->visit(this); 323} 324 325 326ir_visitor_status 327ir_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 349ir_visitor_status 350ir_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 367ir_visitor_status 368ir_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 384ir_visitor_status 385ir_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 396ir_visitor_status 397ir_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 422ir_visitor_status 423ir_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 438ir_visitor_status 439ir_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 453ir_visitor_status 454ir_barrier::accept(ir_hierarchical_visitor *v) 455{ 456 return v->visit(this); 457} 458