Subversion Repositories Kolibri OS

Rev

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_variable_replacement(exec_list *instructions,
  39.                         ir_variable *orig,
  40.                         ir_dereference *repl);
  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.    unsigned 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 = this->callee->parameters.length();
  110.    parameters = new ir_variable *[num_parameters];
  111.  
  112.    /* Generate the declarations for the parameters to our inlined code,
  113.     * and set up the mapping of real function body variables to ours.
  114.     */
  115.    i = 0;
  116.    foreach_two_lists(formal_node, &this->callee->parameters,
  117.                      actual_node, &this->actual_parameters) {
  118.       ir_variable *sig_param = (ir_variable *) formal_node;
  119.       ir_rvalue *param = (ir_rvalue *) actual_node;
  120.  
  121.       /* Generate a new variable for the parameter. */
  122.       if (sig_param->type->contains_opaque()) {
  123.          /* For opaque types, we want the inlined variable references
  124.           * referencing the passed in variable, since that will have
  125.           * the location information, which an assignment of an opaque
  126.           * variable wouldn't.  Fix it up below.
  127.           */
  128.          parameters[i] = NULL;
  129.       } else {
  130.          parameters[i] = sig_param->clone(ctx, ht);
  131.          parameters[i]->data.mode = ir_var_auto;
  132.  
  133.          /* Remove the read-only decoration because we're going to write
  134.           * directly to this variable.  If the cloned variable is left
  135.           * read-only and the inlined function is inside a loop, the loop
  136.           * analysis code will get confused.
  137.           */
  138.          parameters[i]->data.read_only = false;
  139.          next_ir->insert_before(parameters[i]);
  140.       }
  141.  
  142.       /* Move the actual param into our param variable if it's an 'in' type. */
  143.       if (parameters[i] && (sig_param->data.mode == ir_var_function_in ||
  144.                             sig_param->data.mode == ir_var_const_in ||
  145.                             sig_param->data.mode == ir_var_function_inout)) {
  146.          ir_assignment *assign;
  147.  
  148.          assign = new(ctx) ir_assignment(new(ctx) ir_dereference_variable(parameters[i]),
  149.                                          param, NULL);
  150.          next_ir->insert_before(assign);
  151.       }
  152.  
  153.       ++i;
  154.    }
  155.  
  156.    exec_list new_instructions;
  157.  
  158.    /* Generate the inlined body of the function to a new list */
  159.    foreach_in_list(ir_instruction, ir, &callee->body) {
  160.       ir_instruction *new_ir = ir->clone(ctx, ht);
  161.  
  162.       new_instructions.push_tail(new_ir);
  163.       visit_tree(new_ir, replace_return_with_assignment, this->return_deref);
  164.    }
  165.  
  166.    /* If any opaque types were passed in, replace any deref of the
  167.     * opaque variable with a deref of the argument.
  168.     */
  169.    foreach_two_lists(formal_node, &this->callee->parameters,
  170.                      actual_node, &this->actual_parameters) {
  171.       ir_rvalue *const param = (ir_rvalue *) actual_node;
  172.       ir_variable *sig_param = (ir_variable *) formal_node;
  173.  
  174.       if (sig_param->type->contains_opaque()) {
  175.          ir_dereference *deref = param->as_dereference();
  176.  
  177.          assert(deref);
  178.          do_variable_replacement(&new_instructions, sig_param, deref);
  179.       }
  180.    }
  181.  
  182.    /* Now push those new instructions in. */
  183.    next_ir->insert_before(&new_instructions);
  184.  
  185.    /* Copy back the value of any 'out' parameters from the function body
  186.     * variables to our own.
  187.     */
  188.    i = 0;
  189.    foreach_two_lists(formal_node, &this->callee->parameters,
  190.                      actual_node, &this->actual_parameters) {
  191.       ir_rvalue *const param = (ir_rvalue *) actual_node;
  192.       const ir_variable *const sig_param = (ir_variable *) formal_node;
  193.  
  194.       /* Move our param variable into the actual param if it's an 'out' type. */
  195.       if (parameters[i] && (sig_param->data.mode == ir_var_function_out ||
  196.                             sig_param->data.mode == ir_var_function_inout)) {
  197.          ir_assignment *assign;
  198.  
  199.          assign = new(ctx) ir_assignment(param->clone(ctx, NULL)->as_rvalue(),
  200.                                          new(ctx) ir_dereference_variable(parameters[i]),
  201.                                          NULL);
  202.          next_ir->insert_before(assign);
  203.       }
  204.  
  205.       ++i;
  206.    }
  207.  
  208.    delete [] parameters;
  209.  
  210.    hash_table_dtor(ht);
  211. }
  212.  
  213.  
  214. ir_visitor_status
  215. ir_function_inlining_visitor::visit_enter(ir_expression *ir)
  216. {
  217.    (void) ir;
  218.    return visit_continue_with_parent;
  219. }
  220.  
  221.  
  222. ir_visitor_status
  223. ir_function_inlining_visitor::visit_enter(ir_return *ir)
  224. {
  225.    (void) ir;
  226.    return visit_continue_with_parent;
  227. }
  228.  
  229.  
  230. ir_visitor_status
  231. ir_function_inlining_visitor::visit_enter(ir_texture *ir)
  232. {
  233.    (void) ir;
  234.    return visit_continue_with_parent;
  235. }
  236.  
  237.  
  238. ir_visitor_status
  239. ir_function_inlining_visitor::visit_enter(ir_swizzle *ir)
  240. {
  241.    (void) ir;
  242.    return visit_continue_with_parent;
  243. }
  244.  
  245.  
  246. ir_visitor_status
  247. ir_function_inlining_visitor::visit_enter(ir_call *ir)
  248. {
  249.    if (can_inline(ir)) {
  250.       ir->generate_inline(ir);
  251.       ir->remove();
  252.       this->progress = true;
  253.    }
  254.  
  255.    return visit_continue;
  256. }
  257.  
  258.  
  259. /**
  260.  * Replaces references to the "orig" variable with a clone of "repl."
  261.  *
  262.  * From the spec, opaque types can appear in the tree as function
  263.  * (non-out) parameters and as the result of array indexing and
  264.  * structure field selection.  In our builtin implementation, they
  265.  * also appear in the sampler field of an ir_tex instruction.
  266.  */
  267.  
  268. class ir_variable_replacement_visitor : public ir_hierarchical_visitor {
  269. public:
  270.    ir_variable_replacement_visitor(ir_variable *orig, ir_dereference *repl)
  271.    {
  272.       this->orig = orig;
  273.       this->repl = repl;
  274.    }
  275.  
  276.    virtual ~ir_variable_replacement_visitor()
  277.    {
  278.    }
  279.  
  280.    virtual ir_visitor_status visit_leave(ir_call *);
  281.    virtual ir_visitor_status visit_leave(ir_dereference_array *);
  282.    virtual ir_visitor_status visit_leave(ir_dereference_record *);
  283.    virtual ir_visitor_status visit_leave(ir_texture *);
  284.  
  285.    void replace_deref(ir_dereference **deref);
  286.    void replace_rvalue(ir_rvalue **rvalue);
  287.  
  288.    ir_variable *orig;
  289.    ir_dereference *repl;
  290. };
  291.  
  292. void
  293. ir_variable_replacement_visitor::replace_deref(ir_dereference **deref)
  294. {
  295.    ir_dereference_variable *deref_var = (*deref)->as_dereference_variable();
  296.    if (deref_var && deref_var->var == this->orig) {
  297.       *deref = this->repl->clone(ralloc_parent(*deref), NULL);
  298.    }
  299. }
  300.  
  301. void
  302. ir_variable_replacement_visitor::replace_rvalue(ir_rvalue **rvalue)
  303. {
  304.    if (!*rvalue)
  305.       return;
  306.  
  307.    ir_dereference *deref = (*rvalue)->as_dereference();
  308.  
  309.    if (!deref)
  310.       return;
  311.  
  312.    replace_deref(&deref);
  313.    *rvalue = deref;
  314. }
  315.  
  316. ir_visitor_status
  317. ir_variable_replacement_visitor::visit_leave(ir_texture *ir)
  318. {
  319.    replace_deref(&ir->sampler);
  320.  
  321.    return visit_continue;
  322. }
  323.  
  324. ir_visitor_status
  325. ir_variable_replacement_visitor::visit_leave(ir_dereference_array *ir)
  326. {
  327.    replace_rvalue(&ir->array);
  328.    return visit_continue;
  329. }
  330.  
  331. ir_visitor_status
  332. ir_variable_replacement_visitor::visit_leave(ir_dereference_record *ir)
  333. {
  334.    replace_rvalue(&ir->record);
  335.    return visit_continue;
  336. }
  337.  
  338. ir_visitor_status
  339. ir_variable_replacement_visitor::visit_leave(ir_call *ir)
  340. {
  341.    foreach_in_list_safe(ir_rvalue, param, &ir->actual_parameters) {
  342.       ir_rvalue *new_param = param;
  343.       replace_rvalue(&new_param);
  344.  
  345.       if (new_param != param) {
  346.          param->replace_with(new_param);
  347.       }
  348.    }
  349.    return visit_continue;
  350. }
  351.  
  352. static void
  353. do_variable_replacement(exec_list *instructions,
  354.                         ir_variable *orig,
  355.                         ir_dereference *repl)
  356. {
  357.    ir_variable_replacement_visitor v(orig, repl);
  358.  
  359.    visit_list_elements(&v, instructions);
  360. }
  361.