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 if (s != visit_continue_with_parent) { 95 if (this->from) { 96 s = this->from->accept(v); 97 if (s != visit_continue) 98 return (s == visit_continue_with_parent) ? visit_continue : s; 99 } 100 101 if (this->to) { 102 s = this->to->accept(v); 103 if (s != visit_continue) 104 return (s == visit_continue_with_parent) ? visit_continue : s; 105 } 106 107 if (this->increment) { 108 s = this->increment->accept(v); 109 if (s != visit_continue) 110 return (s == visit_continue_with_parent) ? visit_continue : s; 111 } 112 } 113 114 return v->visit_leave(this); 115 } 116 117 118 ir_visitor_status 119 ir_loop_jump::accept(ir_hierarchical_visitor *v) 120 { 121 return v->visit(this); 122 } 123 124 125 ir_visitor_status 126 ir_function_signature::accept(ir_hierarchical_visitor *v) 127 { 128 ir_visitor_status s = v->visit_enter(this); 129 if (s != visit_continue) 130 return (s == visit_continue_with_parent) ? visit_continue : s; 131 132 s = visit_list_elements(v, &this->parameters); 133 if (s == visit_stop) 134 return s; 135 136 s = visit_list_elements(v, &this->body); 137 return (s == visit_stop) ? s : v->visit_leave(this); 138 } 139 140 141 ir_visitor_status 142 ir_function::accept(ir_hierarchical_visitor *v) 143 { 144 ir_visitor_status s = v->visit_enter(this); 145 if (s != visit_continue) 146 return (s == visit_continue_with_parent) ? visit_continue : s; 147 148 s = visit_list_elements(v, &this->signatures, false); 149 return (s == visit_stop) ? s : v->visit_leave(this); 150 } 151 152 153 ir_visitor_status 154 ir_expression::accept(ir_hierarchical_visitor *v) 155 { 156 ir_visitor_status s = v->visit_enter(this); 157 158 if (s != visit_continue) 159 return (s == visit_continue_with_parent) ? visit_continue : s; 160 161 for (unsigned i = 0; i < this->get_num_operands(); i++) { 162 switch (this->operands[i]->accept(v)) { 163 case visit_continue: 164 break; 165 166 case visit_continue_with_parent: 167 // I wish for Java's labeled break-statement here. 168 goto done; 169 170 case visit_stop: 171 return s; 172 } 173 } 174 175 done: 176 return v->visit_leave(this); 177 } 178 179 ir_visitor_status 180 ir_texture::accept(ir_hierarchical_visitor *v) 181 { 182 ir_visitor_status s = v->visit_enter(this); 183 if (s != visit_continue) 184 return (s == visit_continue_with_parent) ? visit_continue : s; 185 186 s = this->sampler->accept(v); 187 if (s != visit_continue) 188 return (s == visit_continue_with_parent) ? visit_continue : s; 189 190 if (this->coordinate) { 191 s = this->coordinate->accept(v); 192 if (s != visit_continue) 193 return (s == visit_continue_with_parent) ? visit_continue : s; 194 } 195 196 if (this->projector) { 197 s = this->projector->accept(v); 198 if (s != visit_continue) 199 return (s == visit_continue_with_parent) ? visit_continue : s; 200 } 201 202 if (this->shadow_comparitor) { 203 s = this->shadow_comparitor->accept(v); 204 if (s != visit_continue) 205 return (s == visit_continue_with_parent) ? visit_continue : s; 206 } 207 208 if (this->offset) { 209 s = this->offset->accept(v); 210 if (s != visit_continue) 211 return (s == visit_continue_with_parent) ? visit_continue : s; 212 } 213 214 switch (this->op) { 215 case ir_tex: 216 break; 217 case ir_txb: 218 s = this->lod_info.bias->accept(v); 219 if (s != visit_continue) 220 return (s == visit_continue_with_parent) ? visit_continue : s; 221 break; 222 case ir_txl: 223 case ir_txf: 224 case ir_txs: 225 s = this->lod_info.lod->accept(v); 226 if (s != visit_continue) 227 return (s == visit_continue_with_parent) ? visit_continue : s; 228 break; 229 case ir_txd: 230 s = this->lod_info.grad.dPdx->accept(v); 231 if (s != visit_continue) 232 return (s == visit_continue_with_parent) ? visit_continue : s; 233 234 s = this->lod_info.grad.dPdy->accept(v); 235 if (s != visit_continue) 236 return (s == visit_continue_with_parent) ? visit_continue : s; 237 break; 238 } 239 240 return (s == visit_stop) ? s : v->visit_leave(this); 241 } 242 243 244 ir_visitor_status 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 257 ir_dereference_variable::accept(ir_hierarchical_visitor *v) 258 { 259 return v->visit(this); 260 } 261 262 263 ir_visitor_status 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 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 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 if (this->condition) 316 s = this->condition->accept(v); 317 318 return (s == visit_stop) ? s : v->visit_leave(this); 319 } 320 321 322 ir_visitor_status 323 ir_constant::accept(ir_hierarchical_visitor *v) 324 { 325 return v->visit(this); 326 } 327 328 329 ir_visitor_status 330 ir_call::accept(ir_hierarchical_visitor *v) 331 { 332 ir_visitor_status s = v->visit_enter(this); 333 if (s != visit_continue) 334 return (s == visit_continue_with_parent) ? visit_continue : s; 335 336 if (this->return_deref != NULL) { 337 v->in_assignee = true; 338 s = this->return_deref->accept(v); 339 v->in_assignee = false; 340 if (s != visit_continue) 341 return (s == visit_continue_with_parent) ? visit_continue : s; 342 } 343 344 s = visit_list_elements(v, &this->actual_parameters, false); 345 if (s == visit_stop) 346 return s; 347 348 return v->visit_leave(this); 349 } 350 351 352 ir_visitor_status 353 ir_return::accept(ir_hierarchical_visitor *v) 354 { 355 ir_visitor_status s = v->visit_enter(this); 356 if (s != visit_continue) 357 return (s == visit_continue_with_parent) ? visit_continue : s; 358 359 ir_rvalue *val = this->get_value(); 360 if (val) { 361 s = val->accept(v); 362 if (s != visit_continue) 363 return (s == visit_continue_with_parent) ? visit_continue : s; 364 } 365 366 return v->visit_leave(this); 367 } 368 369 370 ir_visitor_status 371 ir_discard::accept(ir_hierarchical_visitor *v) 372 { 373 ir_visitor_status s = v->visit_enter(this); 374 if (s != visit_continue) 375 return (s == visit_continue_with_parent) ? visit_continue : s; 376 377 if (this->condition != NULL) { 378 s = this->condition->accept(v); 379 if (s != visit_continue) 380 return (s == visit_continue_with_parent) ? visit_continue : s; 381 } 382 383 return v->visit_leave(this); 384 } 385 386 387 ir_visitor_status 388 ir_if::accept(ir_hierarchical_visitor *v) 389 { 390 ir_visitor_status s = v->visit_enter(this); 391 if (s != visit_continue) 392 return (s == visit_continue_with_parent) ? visit_continue : s; 393 394 s = this->condition->accept(v); 395 if (s != visit_continue) 396 return (s == visit_continue_with_parent) ? visit_continue : s; 397 398 if (s != visit_continue_with_parent) { 399 s = visit_list_elements(v, &this->then_instructions); 400 if (s == visit_stop) 401 return s; 402 } 403 404 if (s != visit_continue_with_parent) { 405 s = visit_list_elements(v, &this->else_instructions); 406 if (s == visit_stop) 407 return s; 408 } 409 410 return v->visit_leave(this); 411 } 412