Home | History | Annotate | Download | only in glsl
      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