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 * \warning 36 * This function will operate correctly if a node being processed is removed 37 * from the list. However, if nodes are added to the list after the node being 38 * processed, some of the added nodes may not be processed. 39 */ 40 ir_visitor_status 41 visit_list_elements(ir_hierarchical_visitor *v, exec_list *l) 42 { 43 ir_instruction *prev_base_ir = v->base_ir; 44 45 foreach_list_safe(n, l) { 46 ir_instruction *const ir = (ir_instruction *) n; 47 v->base_ir = ir; 48 ir_visitor_status s = ir->accept(v); 49 50 if (s != visit_continue) 51 return s; 52 } 53 v->base_ir = prev_base_ir; 54 55 return visit_continue; 56 } 57 58 59 ir_visitor_status 60 ir_variable::accept(ir_hierarchical_visitor *v) 61 { 62 return v->visit(this); 63 } 64 65 66 ir_visitor_status 67 ir_loop::accept(ir_hierarchical_visitor *v) 68 { 69 ir_visitor_status s = v->visit_enter(this); 70 71 if (s != visit_continue) 72 return (s == visit_continue_with_parent) ? visit_continue : s; 73 74 s = visit_list_elements(v, &this->body_instructions); 75 if (s == visit_stop) 76 return s; 77 78 if (s != visit_continue_with_parent) { 79 if (this->from) { 80 s = this->from->accept(v); 81 if (s != visit_continue) 82 return (s == visit_continue_with_parent) ? visit_continue : s; 83 } 84 85 if (this->to) { 86 s = this->to->accept(v); 87 if (s != visit_continue) 88 return (s == visit_continue_with_parent) ? visit_continue : s; 89 } 90 91 if (this->increment) { 92 s = this->increment->accept(v); 93 if (s != visit_continue) 94 return (s == visit_continue_with_parent) ? visit_continue : s; 95 } 96 } 97 98 return v->visit_leave(this); 99 } 100 101 102 ir_visitor_status 103 ir_loop_jump::accept(ir_hierarchical_visitor *v) 104 { 105 return v->visit(this); 106 } 107 108 109 ir_visitor_status 110 ir_function_signature::accept(ir_hierarchical_visitor *v) 111 { 112 ir_visitor_status s = v->visit_enter(this); 113 if (s != visit_continue) 114 return (s == visit_continue_with_parent) ? visit_continue : s; 115 116 s = visit_list_elements(v, &this->parameters); 117 if (s == visit_stop) 118 return s; 119 120 s = visit_list_elements(v, &this->body); 121 return (s == visit_stop) ? s : v->visit_leave(this); 122 } 123 124 125 ir_visitor_status 126 ir_function::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->signatures); 133 return (s == visit_stop) ? s : v->visit_leave(this); 134 } 135 136 137 ir_visitor_status 138 ir_expression::accept(ir_hierarchical_visitor *v) 139 { 140 ir_visitor_status s = v->visit_enter(this); 141 142 if (s != visit_continue) 143 return (s == visit_continue_with_parent) ? visit_continue : s; 144 145 for (unsigned i = 0; i < this->get_num_operands(); i++) { 146 switch (this->operands[i]->accept(v)) { 147 case visit_continue: 148 break; 149 150 case visit_continue_with_parent: 151 // I wish for Java's labeled break-statement here. 152 goto done; 153 154 case visit_stop: 155 return s; 156 } 157 } 158 159 done: 160 return v->visit_leave(this); 161 } 162 163 ir_visitor_status 164 ir_texture::accept(ir_hierarchical_visitor *v) 165 { 166 ir_visitor_status s = v->visit_enter(this); 167 if (s != visit_continue) 168 return (s == visit_continue_with_parent) ? visit_continue : s; 169 170 s = this->sampler->accept(v); 171 if (s != visit_continue) 172 return (s == visit_continue_with_parent) ? visit_continue : s; 173 174 s = this->coordinate->accept(v); 175 if (s != visit_continue) 176 return (s == visit_continue_with_parent) ? visit_continue : s; 177 178 if (this->projector) { 179 s = this->projector->accept(v); 180 if (s != visit_continue) 181 return (s == visit_continue_with_parent) ? visit_continue : s; 182 } 183 184 if (this->shadow_comparitor) { 185 s = this->shadow_comparitor->accept(v); 186 if (s != visit_continue) 187 return (s == visit_continue_with_parent) ? visit_continue : s; 188 } 189 190 switch (this->op) { 191 case ir_tex: 192 break; 193 case ir_txb: 194 s = this->lod_info.bias->accept(v); 195 if (s != visit_continue) 196 return (s == visit_continue_with_parent) ? visit_continue : s; 197 break; 198 case ir_txl: 199 case ir_txf: 200 s = this->lod_info.lod->accept(v); 201 if (s != visit_continue) 202 return (s == visit_continue_with_parent) ? visit_continue : s; 203 break; 204 case ir_txd: 205 s = this->lod_info.grad.dPdx->accept(v); 206 if (s != visit_continue) 207 return (s == visit_continue_with_parent) ? visit_continue : s; 208 209 s = this->lod_info.grad.dPdy->accept(v); 210 if (s != visit_continue) 211 return (s == visit_continue_with_parent) ? visit_continue : s; 212 break; 213 } 214 215 return (s == visit_stop) ? s : v->visit_leave(this); 216 } 217 218 219 ir_visitor_status 220 ir_swizzle::accept(ir_hierarchical_visitor *v) 221 { 222 ir_visitor_status s = v->visit_enter(this); 223 if (s != visit_continue) 224 return (s == visit_continue_with_parent) ? visit_continue : s; 225 226 s = this->val->accept(v); 227 return (s == visit_stop) ? s : v->visit_leave(this); 228 } 229 230 231 ir_visitor_status 232 ir_dereference_variable::accept(ir_hierarchical_visitor *v) 233 { 234 return v->visit(this); 235 } 236 237 238 ir_visitor_status 239 ir_dereference_array::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 /* The array index is not the target of the assignment, so clear the 246 * 'in_assignee' flag. Restore it after returning from the array index. 247 */ 248 const bool was_in_assignee = v->in_assignee; 249 v->in_assignee = false; 250 s = this->array_index->accept(v); 251 v->in_assignee = was_in_assignee; 252 253 if (s != visit_continue) 254 return (s == visit_continue_with_parent) ? visit_continue : s; 255 256 s = this->array->accept(v); 257 return (s == visit_stop) ? s : v->visit_leave(this); 258 } 259 260 261 ir_visitor_status 262 ir_dereference_record::accept(ir_hierarchical_visitor *v) 263 { 264 ir_visitor_status s = v->visit_enter(this); 265 if (s != visit_continue) 266 return (s == visit_continue_with_parent) ? visit_continue : s; 267 268 s = this->record->accept(v); 269 return (s == visit_stop) ? s : v->visit_leave(this); 270 } 271 272 273 ir_visitor_status 274 ir_assignment::accept(ir_hierarchical_visitor *v) 275 { 276 ir_visitor_status s = v->visit_enter(this); 277 if (s != visit_continue) 278 return (s == visit_continue_with_parent) ? visit_continue : s; 279 280 v->in_assignee = true; 281 s = this->lhs->accept(v); 282 v->in_assignee = false; 283 if (s != visit_continue) 284 return (s == visit_continue_with_parent) ? visit_continue : s; 285 286 s = this->rhs->accept(v); 287 if (s != visit_continue) 288 return (s == visit_continue_with_parent) ? visit_continue : s; 289 290 if (this->condition) 291 s = this->condition->accept(v); 292 293 return (s == visit_stop) ? s : v->visit_leave(this); 294 } 295 296 297 ir_visitor_status 298 ir_constant::accept(ir_hierarchical_visitor *v) 299 { 300 return v->visit(this); 301 } 302 303 304 ir_visitor_status 305 ir_call::accept(ir_hierarchical_visitor *v) 306 { 307 ir_visitor_status s = v->visit_enter(this); 308 if (s != visit_continue) 309 return (s == visit_continue_with_parent) ? visit_continue : s; 310 311 s = visit_list_elements(v, &this->actual_parameters); 312 if (s == visit_stop) 313 return s; 314 315 return v->visit_leave(this); 316 } 317 318 319 ir_visitor_status 320 ir_return::accept(ir_hierarchical_visitor *v) 321 { 322 ir_visitor_status s = v->visit_enter(this); 323 if (s != visit_continue) 324 return (s == visit_continue_with_parent) ? visit_continue : s; 325 326 ir_rvalue *val = this->get_value(); 327 if (val) { 328 s = val->accept(v); 329 if (s != visit_continue) 330 return (s == visit_continue_with_parent) ? visit_continue : s; 331 } 332 333 return v->visit_leave(this); 334 } 335 336 337 ir_visitor_status 338 ir_discard::accept(ir_hierarchical_visitor *v) 339 { 340 ir_visitor_status s = v->visit_enter(this); 341 if (s != visit_continue) 342 return (s == visit_continue_with_parent) ? visit_continue : s; 343 344 if (this->condition != NULL) { 345 s = this->condition->accept(v); 346 if (s != visit_continue) 347 return (s == visit_continue_with_parent) ? visit_continue : s; 348 } 349 350 return v->visit_leave(this); 351 } 352 353 354 ir_visitor_status 355 ir_if::accept(ir_hierarchical_visitor *v) 356 { 357 ir_visitor_status s = v->visit_enter(this); 358 if (s != visit_continue) 359 return (s == visit_continue_with_parent) ? visit_continue : s; 360 361 s = this->condition->accept(v); 362 if (s != visit_continue) 363 return (s == visit_continue_with_parent) ? visit_continue : s; 364 365 if (s != visit_continue_with_parent) { 366 s = visit_list_elements(v, &this->then_instructions); 367 if (s == visit_stop) 368 return s; 369 } 370 371 if (s != visit_continue_with_parent) { 372 s = visit_list_elements(v, &this->else_instructions); 373 if (s == visit_stop) 374 return s; 375 } 376 377 return v->visit_leave(this); 378 } 379