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 switch (this->op) { 194 case ir_tex: 195 case ir_lod: 196 case ir_query_levels: 197 case ir_texture_samples: 198 case ir_samples_identical: 199 break; 200 case ir_txb: 201 s = this->lod_info.bias->accept(v); 202 if (s != visit_continue) 203 return (s == visit_continue_with_parent) ? visit_continue : s; 204 break; 205 case ir_txl: 206 case ir_txf: 207 case ir_txs: 208 s = this->lod_info.lod->accept(v); 209 if (s != visit_continue) 210 return (s == visit_continue_with_parent) ? visit_continue : s; 211 break; 212 case ir_txf_ms: 213 s = this->lod_info.sample_index->accept(v); 214 if (s != visit_continue) 215 return (s == visit_continue_with_parent) ? visit_continue : s; 216 break; 217 case ir_txd: 218 s = this->lod_info.grad.dPdx->accept(v); 219 if (s != visit_continue) 220 return (s == visit_continue_with_parent) ? visit_continue : s; 221 222 s = this->lod_info.grad.dPdy->accept(v); 223 if (s != visit_continue) 224 return (s == visit_continue_with_parent) ? visit_continue : s; 225 break; 226 case ir_tg4: 227 s = this->lod_info.component->accept(v); 228 if (s != visit_continue) 229 return (s == visit_continue_with_parent) ? visit_continue : s; 230 break; 231 } 232 233 assert(s == visit_continue); 234 return v->visit_leave(this); 235} 236 237 238ir_visitor_status 239ir_swizzle::accept(ir_hierarchical_visitor *v) 240{ 241 ir_visitor_status s = v->visit_enter(this); 242 if (s != visit_continue) 243 return (s == visit_continue_with_parent) ? visit_continue : s; 244 245 s = this->val->accept(v); 246 return (s == visit_stop) ? s : v->visit_leave(this); 247} 248 249 250ir_visitor_status 251ir_dereference_variable::accept(ir_hierarchical_visitor *v) 252{ 253 return v->visit(this); 254} 255 256 257ir_visitor_status 258ir_dereference_array::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 /* The array index is not the target of the assignment, so clear the 265 * 'in_assignee' flag. Restore it after returning from the array index. 266 */ 267 const bool was_in_assignee = v->in_assignee; 268 v->in_assignee = false; 269 s = this->array_index->accept(v); 270 v->in_assignee = was_in_assignee; 271 272 if (s != visit_continue) 273 return (s == visit_continue_with_parent) ? visit_continue : s; 274 275 s = this->array->accept(v); 276 return (s == visit_stop) ? s : v->visit_leave(this); 277} 278 279 280ir_visitor_status 281ir_dereference_record::accept(ir_hierarchical_visitor *v) 282{ 283 ir_visitor_status s = v->visit_enter(this); 284 if (s != visit_continue) 285 return (s == visit_continue_with_parent) ? visit_continue : s; 286 287 s = this->record->accept(v); 288 return (s == visit_stop) ? s : v->visit_leave(this); 289} 290 291 292ir_visitor_status 293ir_assignment::accept(ir_hierarchical_visitor *v) 294{ 295 ir_visitor_status s = v->visit_enter(this); 296 if (s != visit_continue) 297 return (s == visit_continue_with_parent) ? visit_continue : s; 298 299 v->in_assignee = true; 300 s = this->lhs->accept(v); 301 v->in_assignee = false; 302 if (s != visit_continue) 303 return (s == visit_continue_with_parent) ? visit_continue : s; 304 305 s = this->rhs->accept(v); 306 if (s != visit_continue) 307 return (s == visit_continue_with_parent) ? visit_continue : s; 308 309 if (this->condition) 310 s = this->condition->accept(v); 311 312 return (s == visit_stop) ? s : v->visit_leave(this); 313} 314 315 316ir_visitor_status 317ir_constant::accept(ir_hierarchical_visitor *v) 318{ 319 return v->visit(this); 320} 321 322 323ir_visitor_status 324ir_call::accept(ir_hierarchical_visitor *v) 325{ 326 ir_visitor_status s = v->visit_enter(this); 327 if (s != visit_continue) 328 return (s == visit_continue_with_parent) ? visit_continue : s; 329 330 if (this->return_deref != NULL) { 331 v->in_assignee = true; 332 s = this->return_deref->accept(v); 333 v->in_assignee = false; 334 if (s != visit_continue) 335 return (s == visit_continue_with_parent) ? visit_continue : s; 336 } 337 338 s = visit_list_elements(v, &this->actual_parameters, false); 339 if (s == visit_stop) 340 return s; 341 342 return v->visit_leave(this); 343} 344 345 346ir_visitor_status 347ir_return::accept(ir_hierarchical_visitor *v) 348{ 349 ir_visitor_status s = v->visit_enter(this); 350 if (s != visit_continue) 351 return (s == visit_continue_with_parent) ? visit_continue : s; 352 353 ir_rvalue *val = this->get_value(); 354 if (val) { 355 s = val->accept(v); 356 if (s != visit_continue) 357 return (s == visit_continue_with_parent) ? visit_continue : s; 358 } 359 360 return v->visit_leave(this); 361} 362 363 364ir_visitor_status 365ir_discard::accept(ir_hierarchical_visitor *v) 366{ 367 ir_visitor_status s = v->visit_enter(this); 368 if (s != visit_continue) 369 return (s == visit_continue_with_parent) ? visit_continue : s; 370 371 if (this->condition != NULL) { 372 s = this->condition->accept(v); 373 if (s != visit_continue) 374 return (s == visit_continue_with_parent) ? visit_continue : s; 375 } 376 377 return v->visit_leave(this); 378} 379 380 381ir_visitor_status 382ir_demote::accept(ir_hierarchical_visitor *v) 383{ 384 ir_visitor_status s = v->visit_enter(this); 385 386 if (s != visit_continue) 387 return (s == visit_continue_with_parent) ? visit_continue : s; 388 389 return v->visit_leave(this); 390} 391 392 393ir_visitor_status 394ir_if::accept(ir_hierarchical_visitor *v) 395{ 396 ir_visitor_status s = v->visit_enter(this); 397 if (s != visit_continue) 398 return (s == visit_continue_with_parent) ? visit_continue : s; 399 400 s = this->condition->accept(v); 401 if (s != visit_continue) 402 return (s == visit_continue_with_parent) ? visit_continue : s; 403 404 if (s != visit_continue_with_parent) { 405 s = visit_list_elements(v, &this->then_instructions); 406 if (s == visit_stop) 407 return s; 408 } 409 410 if (s != visit_continue_with_parent) { 411 s = visit_list_elements(v, &this->else_instructions); 412 if (s == visit_stop) 413 return s; 414 } 415 416 return v->visit_leave(this); 417} 418 419ir_visitor_status 420ir_emit_vertex::accept(ir_hierarchical_visitor *v) 421{ 422 ir_visitor_status s = v->visit_enter(this); 423 if (s != visit_continue) 424 return (s == visit_continue_with_parent) ? visit_continue : s; 425 426 s = this->stream->accept(v); 427 if (s != visit_continue) 428 return (s == visit_continue_with_parent) ? visit_continue : s; 429 430 assert(s == visit_continue); 431 return v->visit_leave(this); 432} 433 434 435ir_visitor_status 436ir_end_primitive::accept(ir_hierarchical_visitor *v) 437{ 438 ir_visitor_status s = v->visit_enter(this); 439 if (s != visit_continue) 440 return (s == visit_continue_with_parent) ? visit_continue : s; 441 442 s = this->stream->accept(v); 443 if (s != visit_continue) 444 return (s == visit_continue_with_parent) ? visit_continue : s; 445 446 assert(s == visit_continue); 447 return v->visit_leave(this); 448} 449 450ir_visitor_status 451ir_barrier::accept(ir_hierarchical_visitor *v) 452{ 453 return v->visit(this); 454} 455