Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | RSS feed

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