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_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 68 ir_rvalue::accept(ir_hierarchical_visitor *v) 69 { 70 return v->visit(this); 71 } 72 73 74 ir_visitor_status 75 ir_variable::accept(ir_hierarchical_visitor *v) 76 { 77 return v->visit(this); 78 } 79 80 81 ir_visitor_status 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 98 ir_loop_jump::accept(ir_hierarchical_visitor *v) 99 { 100 return v->visit(this); 101 } 102 103 104 ir_visitor_status 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 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 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->get_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 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 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 return (s == visit_stop) ? s : v->visit_leave(this); 234 } 235 236 237 ir_visitor_status 238 ir_swizzle::accept(ir_hierarchical_visitor *v) 239 { 240 ir_visitor_status s = v->visit_enter(this); 241 if (s != visit_continue) 242 return (s == visit_continue_with_parent) ? visit_continue : s; 243 244 s = this->val->accept(v); 245 return (s == visit_stop) ? s : v->visit_leave(this); 246 } 247 248 249 ir_visitor_status 250 ir_dereference_variable::accept(ir_hierarchical_visitor *v) 251 { 252 return v->visit(this); 253 } 254 255 256 ir_visitor_status 257 ir_dereference_array::accept(ir_hierarchical_visitor *v) 258 { 259 ir_visitor_status s = v->visit_enter(this); 260 if (s != visit_continue) 261 return (s == visit_continue_with_parent) ? visit_continue : s; 262 263 /* The array index is not the target of the assignment, so clear the 264 * 'in_assignee' flag. Restore it after returning from the array index. 265 */ 266 const bool was_in_assignee = v->in_assignee; 267 v->in_assignee = false; 268 s = this->array_index->accept(v); 269 v->in_assignee = was_in_assignee; 270 271 if (s != visit_continue) 272 return (s == visit_continue_with_parent) ? visit_continue : s; 273 274 s = this->array->accept(v); 275 return (s == visit_stop) ? s : v->visit_leave(this); 276 } 277 278 279 ir_visitor_status 280 ir_dereference_record::accept(ir_hierarchical_visitor *v) 281 { 282 ir_visitor_status s = v->visit_enter(this); 283 if (s != visit_continue) 284 return (s == visit_continue_with_parent) ? visit_continue : s; 285 286 s = this->record->accept(v); 287 return (s == visit_stop) ? s : v->visit_leave(this); 288 } 289 290 291 ir_visitor_status 292 ir_assignment::accept(ir_hierarchical_visitor *v) 293 { 294 ir_visitor_status s = v->visit_enter(this); 295 if (s != visit_continue) 296 return (s == visit_continue_with_parent) ? visit_continue : s; 297 298 v->in_assignee = true; 299 s = this->lhs->accept(v); 300 v->in_assignee = false; 301 if (s != visit_continue) 302 return (s == visit_continue_with_parent) ? visit_continue : s; 303 304 s = this->rhs->accept(v); 305 if (s != visit_continue) 306 return (s == visit_continue_with_parent) ? visit_continue : s; 307 308 if (this->condition) 309 s = this->condition->accept(v); 310 311 return (s == visit_stop) ? s : v->visit_leave(this); 312 } 313 314 315 ir_visitor_status 316 ir_constant::accept(ir_hierarchical_visitor *v) 317 { 318 return v->visit(this); 319 } 320 321 322 ir_visitor_status 323 ir_call::accept(ir_hierarchical_visitor *v) 324 { 325 ir_visitor_status s = v->visit_enter(this); 326 if (s != visit_continue) 327 return (s == visit_continue_with_parent) ? visit_continue : s; 328 329 if (this->return_deref != NULL) { 330 v->in_assignee = true; 331 s = this->return_deref->accept(v); 332 v->in_assignee = false; 333 if (s != visit_continue) 334 return (s == visit_continue_with_parent) ? visit_continue : s; 335 } 336 337 s = visit_list_elements(v, &this->actual_parameters, false); 338 if (s == visit_stop) 339 return s; 340 341 return v->visit_leave(this); 342 } 343 344 345 ir_visitor_status 346 ir_return::accept(ir_hierarchical_visitor *v) 347 { 348 ir_visitor_status s = v->visit_enter(this); 349 if (s != visit_continue) 350 return (s == visit_continue_with_parent) ? visit_continue : s; 351 352 ir_rvalue *val = this->get_value(); 353 if (val) { 354 s = val->accept(v); 355 if (s != visit_continue) 356 return (s == visit_continue_with_parent) ? visit_continue : s; 357 } 358 359 return v->visit_leave(this); 360 } 361 362 363 ir_visitor_status 364 ir_discard::accept(ir_hierarchical_visitor *v) 365 { 366 ir_visitor_status s = v->visit_enter(this); 367 if (s != visit_continue) 368 return (s == visit_continue_with_parent) ? visit_continue : s; 369 370 if (this->condition != NULL) { 371 s = this->condition->accept(v); 372 if (s != visit_continue) 373 return (s == visit_continue_with_parent) ? visit_continue : s; 374 } 375 376 return v->visit_leave(this); 377 } 378 379 380 ir_visitor_status 381 ir_if::accept(ir_hierarchical_visitor *v) 382 { 383 ir_visitor_status s = v->visit_enter(this); 384 if (s != visit_continue) 385 return (s == visit_continue_with_parent) ? visit_continue : s; 386 387 s = this->condition->accept(v); 388 if (s != visit_continue) 389 return (s == visit_continue_with_parent) ? visit_continue : s; 390 391 if (s != visit_continue_with_parent) { 392 s = visit_list_elements(v, &this->then_instructions); 393 if (s == visit_stop) 394 return s; 395 } 396 397 if (s != visit_continue_with_parent) { 398 s = visit_list_elements(v, &this->else_instructions); 399 if (s == visit_stop) 400 return s; 401 } 402 403 return v->visit_leave(this); 404 } 405 406 ir_visitor_status 407 ir_emit_vertex::accept(ir_hierarchical_visitor *v) 408 { 409 ir_visitor_status s = v->visit_enter(this); 410 if (s != visit_continue) 411 return (s == visit_continue_with_parent) ? visit_continue : s; 412 413 s = this->stream->accept(v); 414 if (s != visit_continue) 415 return (s == visit_continue_with_parent) ? visit_continue : s; 416 417 return (s == visit_stop) ? s : v->visit_leave(this); 418 } 419 420 421 ir_visitor_status 422 ir_end_primitive::accept(ir_hierarchical_visitor *v) 423 { 424 ir_visitor_status s = v->visit_enter(this); 425 if (s != visit_continue) 426 return (s == visit_continue_with_parent) ? visit_continue : s; 427 428 s = this->stream->accept(v); 429 if (s != visit_continue) 430 return (s == visit_continue_with_parent) ? visit_continue : s; 431 432 return (s == visit_stop) ? s : v->visit_leave(this); 433 } 434 435 ir_visitor_status 436 ir_barrier::accept(ir_hierarchical_visitor *v) 437 { 438 return v->visit(this); 439 } 440