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 /**
     25  * \file opt_function_inlining.cpp
     26  *
     27  * Replaces calls to functions with the body of the function.
     28  */
     29 
     30 #include <inttypes.h>
     31 #include "ir.h"
     32 #include "ir_visitor.h"
     33 #include "ir_function_inlining.h"
     34 #include "ir_expression_flattening.h"
     35 #include "glsl_types.h"
     36 #include "program/hash_table.h"
     37 
     38 static void
     39 do_sampler_replacement(exec_list *instructions,
     40 		       ir_variable *sampler,
     41 		       ir_dereference *deref);
     42 
     43 class ir_function_inlining_visitor : public ir_hierarchical_visitor {
     44 public:
     45    ir_function_inlining_visitor()
     46    {
     47       progress = false;
     48    }
     49 
     50    virtual ~ir_function_inlining_visitor()
     51    {
     52       /* empty */
     53    }
     54 
     55    virtual ir_visitor_status visit_enter(ir_expression *);
     56    virtual ir_visitor_status visit_enter(ir_call *);
     57    virtual ir_visitor_status visit_enter(ir_assignment *);
     58    virtual ir_visitor_status visit_enter(ir_return *);
     59    virtual ir_visitor_status visit_enter(ir_texture *);
     60    virtual ir_visitor_status visit_enter(ir_swizzle *);
     61 
     62    bool progress;
     63 };
     64 
     65 
     66 bool
     67 automatic_inlining_predicate(ir_instruction *ir)
     68 {
     69    ir_call *call = ir->as_call();
     70 
     71    if (call && can_inline(call))
     72       return true;
     73 
     74    return false;
     75 }
     76 
     77 bool
     78 do_function_inlining(exec_list *instructions)
     79 {
     80    ir_function_inlining_visitor v;
     81 
     82    do_expression_flattening(instructions, automatic_inlining_predicate);
     83 
     84    v.run(instructions);
     85 
     86    return v.progress;
     87 }
     88 
     89 static void
     90 replace_return_with_assignment(ir_instruction *ir, void *data)
     91 {
     92    void *ctx = hieralloc_parent(ir);
     93    ir_variable *retval = (ir_variable *)data;
     94    ir_return *ret = ir->as_return();
     95 
     96    if (ret) {
     97       if (ret->value) {
     98 	 ir_rvalue *lhs = new(ctx) ir_dereference_variable(retval);
     99 	 ret->replace_with(new(ctx) ir_assignment(lhs, ret->value, NULL));
    100       } else {
    101 	 /* un-valued return has to be the last return, or we shouldn't
    102 	  * have reached here. (see can_inline()).
    103 	  */
    104 	 assert(ret->next->is_tail_sentinel());
    105 	 ret->remove();
    106       }
    107    }
    108 }
    109 
    110 ir_rvalue *
    111 ir_call::generate_inline(ir_instruction *next_ir)
    112 {
    113    void *ctx = hieralloc_parent(this);
    114    ir_variable **parameters;
    115    int num_parameters;
    116    int i;
    117    ir_variable *retval = NULL;
    118    struct hash_table *ht;
    119 
    120    ht = hash_table_ctor(0, hash_table_pointer_hash, hash_table_pointer_compare);
    121 
    122    num_parameters = 0;
    123    foreach_iter(exec_list_iterator, iter_sig, this->callee->parameters)
    124       num_parameters++;
    125 
    126    parameters = new ir_variable *[num_parameters];
    127 
    128    /* Generate storage for the return value. */
    129    if (this->callee->return_type) {
    130       retval = new(ctx) ir_variable(this->callee->return_type, "_ret_val",
    131 				    ir_var_auto);
    132       next_ir->insert_before(retval);
    133    }
    134 
    135    /* Generate the declarations for the parameters to our inlined code,
    136     * and set up the mapping of real function body variables to ours.
    137     */
    138    i = 0;
    139    exec_list_iterator sig_param_iter = this->callee->parameters.iterator();
    140    exec_list_iterator param_iter = this->actual_parameters.iterator();
    141    for (i = 0; i < num_parameters; i++) {
    142       ir_variable *sig_param = (ir_variable *) sig_param_iter.get();
    143       ir_rvalue *param = (ir_rvalue *) param_iter.get();
    144 
    145       /* Generate a new variable for the parameter. */
    146       if (sig_param->type->base_type == GLSL_TYPE_SAMPLER) {
    147 	 /* For samplers, we want the inlined sampler references
    148 	  * referencing the passed in sampler variable, since that
    149 	  * will have the location information, which an assignment of
    150 	  * a sampler wouldn't.  Fix it up below.
    151 	  */
    152 	 parameters[i] = NULL;
    153       } else {
    154 	 parameters[i] = sig_param->clone(ctx, ht);
    155 	 parameters[i]->mode = ir_var_auto;
    156 
    157 	 /* Remove the read-only decoration becuase we're going to write
    158 	  * directly to this variable.  If the cloned variable is left
    159 	  * read-only and the inlined function is inside a loop, the loop
    160 	  * analysis code will get confused.
    161 	  */
    162 	 parameters[i]->read_only = false;
    163 	 next_ir->insert_before(parameters[i]);
    164       }
    165 
    166       /* Move the actual param into our param variable if it's an 'in' type. */
    167       if (parameters[i] && (sig_param->mode == ir_var_in ||
    168 			    sig_param->mode == ir_var_inout)) {
    169 	 ir_assignment *assign;
    170 
    171 	 assign = new(ctx) ir_assignment(new(ctx) ir_dereference_variable(parameters[i]),
    172 					 param, NULL);
    173 	 next_ir->insert_before(assign);
    174       }
    175 
    176       sig_param_iter.next();
    177       param_iter.next();
    178    }
    179 
    180    exec_list new_instructions;
    181 
    182    /* Generate the inlined body of the function to a new list */
    183    foreach_iter(exec_list_iterator, iter, callee->body) {
    184       ir_instruction *ir = (ir_instruction *)iter.get();
    185       ir_instruction *new_ir = ir->clone(ctx, ht);
    186 
    187       new_instructions.push_tail(new_ir);
    188       visit_tree(new_ir, replace_return_with_assignment, retval);
    189    }
    190 
    191    /* If any samplers were passed in, replace any deref of the sampler
    192     * with a deref of the sampler argument.
    193     */
    194    param_iter = this->actual_parameters.iterator();
    195    sig_param_iter = this->callee->parameters.iterator();
    196    for (i = 0; i < num_parameters; i++) {
    197       ir_instruction *const param = (ir_instruction *) param_iter.get();
    198       ir_variable *sig_param = (ir_variable *) sig_param_iter.get();
    199 
    200       if (sig_param->type->base_type == GLSL_TYPE_SAMPLER) {
    201 	 ir_dereference *deref = param->as_dereference();
    202 
    203 	 assert(deref);
    204 	 do_sampler_replacement(&new_instructions, sig_param, deref);
    205       }
    206       param_iter.next();
    207       sig_param_iter.next();
    208    }
    209 
    210    /* Now push those new instructions in. */
    211    foreach_iter(exec_list_iterator, iter, new_instructions) {
    212       ir_instruction *ir = (ir_instruction *)iter.get();
    213       next_ir->insert_before(ir);
    214    }
    215 
    216    /* Copy back the value of any 'out' parameters from the function body
    217     * variables to our own.
    218     */
    219    i = 0;
    220    param_iter = this->actual_parameters.iterator();
    221    sig_param_iter = this->callee->parameters.iterator();
    222    for (i = 0; i < num_parameters; i++) {
    223       ir_instruction *const param = (ir_instruction *) param_iter.get();
    224       const ir_variable *const sig_param = (ir_variable *) sig_param_iter.get();
    225 
    226       /* Move our param variable into the actual param if it's an 'out' type. */
    227       if (parameters[i] && (sig_param->mode == ir_var_out ||
    228 			    sig_param->mode == ir_var_inout)) {
    229 	 ir_assignment *assign;
    230 
    231 	 assign = new(ctx) ir_assignment(param->clone(ctx, NULL)->as_rvalue(),
    232 					 new(ctx) ir_dereference_variable(parameters[i]),
    233 					 NULL);
    234 	 next_ir->insert_before(assign);
    235       }
    236 
    237       param_iter.next();
    238       sig_param_iter.next();
    239    }
    240 
    241    delete [] parameters;
    242 
    243    hash_table_dtor(ht);
    244 
    245    if (retval)
    246       return new(ctx) ir_dereference_variable(retval);
    247    else
    248       return NULL;
    249 }
    250 
    251 
    252 ir_visitor_status
    253 ir_function_inlining_visitor::visit_enter(ir_expression *ir)
    254 {
    255    (void) ir;
    256    return visit_continue_with_parent;
    257 }
    258 
    259 
    260 ir_visitor_status
    261 ir_function_inlining_visitor::visit_enter(ir_return *ir)
    262 {
    263    (void) ir;
    264    return visit_continue_with_parent;
    265 }
    266 
    267 
    268 ir_visitor_status
    269 ir_function_inlining_visitor::visit_enter(ir_texture *ir)
    270 {
    271    (void) ir;
    272    return visit_continue_with_parent;
    273 }
    274 
    275 
    276 ir_visitor_status
    277 ir_function_inlining_visitor::visit_enter(ir_swizzle *ir)
    278 {
    279    (void) ir;
    280    return visit_continue_with_parent;
    281 }
    282 
    283 
    284 ir_visitor_status
    285 ir_function_inlining_visitor::visit_enter(ir_call *ir)
    286 {
    287    if (can_inline(ir)) {
    288       /* If the call was part of some tree, then it should have been
    289        * flattened out or we shouldn't have seen it because of a
    290        * visit_continue_with_parent in this visitor.
    291        */
    292       assert(ir == base_ir);
    293 
    294       (void) ir->generate_inline(ir);
    295       ir->remove();
    296       this->progress = true;
    297    }
    298 
    299    return visit_continue;
    300 }
    301 
    302 
    303 ir_visitor_status
    304 ir_function_inlining_visitor::visit_enter(ir_assignment *ir)
    305 {
    306    ir_call *call = ir->rhs->as_call();
    307    if (!call || !can_inline(call))
    308       return visit_continue;
    309 
    310    /* generates the parameter setup, function body, and returns the return
    311     * value of the function
    312     */
    313    ir_rvalue *rhs = call->generate_inline(ir);
    314    assert(rhs);
    315 
    316    ir->rhs = rhs;
    317    this->progress = true;
    318 
    319    return visit_continue;
    320 }
    321 
    322 /**
    323  * Replaces references to the "sampler" variable with a clone of "deref."
    324  *
    325  * From the spec, samplers can appear in the tree as function
    326  * (non-out) parameters and as the result of array indexing and
    327  * structure field selection.  In our builtin implementation, they
    328  * also appear in the sampler field of an ir_tex instruction.
    329  */
    330 
    331 class ir_sampler_replacement_visitor : public ir_hierarchical_visitor {
    332 public:
    333    ir_sampler_replacement_visitor(ir_variable *sampler, ir_dereference *deref)
    334    {
    335       this->sampler = sampler;
    336       this->deref = deref;
    337    }
    338 
    339    virtual ~ir_sampler_replacement_visitor()
    340    {
    341    }
    342 
    343    virtual ir_visitor_status visit_leave(ir_call *);
    344    virtual ir_visitor_status visit_leave(ir_dereference_array *);
    345    virtual ir_visitor_status visit_leave(ir_dereference_record *);
    346    virtual ir_visitor_status visit_leave(ir_texture *);
    347 
    348    void replace_deref(ir_dereference **deref);
    349    void replace_rvalue(ir_rvalue **rvalue);
    350 
    351    ir_variable *sampler;
    352    ir_dereference *deref;
    353 };
    354 
    355 void
    356 ir_sampler_replacement_visitor::replace_deref(ir_dereference **deref)
    357 {
    358    ir_dereference_variable *deref_var = (*deref)->as_dereference_variable();
    359    if (deref_var && deref_var->var == this->sampler) {
    360       *deref = this->deref->clone(hieralloc_parent(*deref), NULL);
    361    }
    362 }
    363 
    364 void
    365 ir_sampler_replacement_visitor::replace_rvalue(ir_rvalue **rvalue)
    366 {
    367    if (!*rvalue)
    368       return;
    369 
    370    ir_dereference *deref = (*rvalue)->as_dereference();
    371 
    372    if (!deref)
    373       return;
    374 
    375    replace_deref(&deref);
    376    *rvalue = deref;
    377 }
    378 
    379 ir_visitor_status
    380 ir_sampler_replacement_visitor::visit_leave(ir_texture *ir)
    381 {
    382    replace_deref(&ir->sampler);
    383 
    384    return visit_continue;
    385 }
    386 
    387 ir_visitor_status
    388 ir_sampler_replacement_visitor::visit_leave(ir_dereference_array *ir)
    389 {
    390    replace_rvalue(&ir->array);
    391    return visit_continue;
    392 }
    393 
    394 ir_visitor_status
    395 ir_sampler_replacement_visitor::visit_leave(ir_dereference_record *ir)
    396 {
    397    replace_rvalue(&ir->record);
    398    return visit_continue;
    399 }
    400 
    401 ir_visitor_status
    402 ir_sampler_replacement_visitor::visit_leave(ir_call *ir)
    403 {
    404    foreach_iter(exec_list_iterator, iter, *ir) {
    405       ir_rvalue *param = (ir_rvalue *)iter.get();
    406       ir_rvalue *new_param = param;
    407       replace_rvalue(&new_param);
    408 
    409       if (new_param != param) {
    410 	 param->replace_with(new_param);
    411       }
    412    }
    413    return visit_continue;
    414 }
    415 
    416 static void
    417 do_sampler_replacement(exec_list *instructions,
    418 		       ir_variable *sampler,
    419 		       ir_dereference *deref)
    420 {
    421    ir_sampler_replacement_visitor v(sampler, deref);
    422 
    423    visit_list_elements(&v, instructions);
    424 }
    425