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_array_splitting.cpp
  26.  *
  27.  * If an array is always dereferenced with a constant index, then
  28.  * split it apart into its elements, making it more amenable to other
  29.  * optimization passes.
  30.  *
  31.  * This skips uniform/varying arrays, which would need careful
  32.  * handling due to their ir->location fields tying them to the GL API
  33.  * and other shader stages.
  34.  */
  35.  
  36. #include "ir.h"
  37. #include "ir_visitor.h"
  38. #include "ir_rvalue_visitor.h"
  39. #include "glsl_types.h"
  40.  
  41. static bool debug = false;
  42.  
  43. namespace opt_array_splitting {
  44.  
  45. class variable_entry : public exec_node
  46. {
  47. public:
  48.    variable_entry(ir_variable *var)
  49.    {
  50.       this->var = var;
  51.       this->split = true;
  52.       this->declaration = false;
  53.       this->components = NULL;
  54.       this->mem_ctx = NULL;
  55.       if (var->type->is_array())
  56.          this->size = var->type->length;
  57.       else
  58.          this->size = var->type->matrix_columns;
  59.    }
  60.  
  61.    ir_variable *var; /* The key: the variable's pointer. */
  62.    unsigned size; /* array length or matrix columns */
  63.  
  64.    /** Whether this array should be split or not. */
  65.    bool split;
  66.  
  67.    /* If the variable had a decl we can work with in the instruction
  68.     * stream.  We can't do splitting on function arguments, which
  69.     * don't get this variable set.
  70.     */
  71.    bool declaration;
  72.  
  73.    ir_variable **components;
  74.  
  75.    /** ralloc_parent(this->var) -- the shader's talloc context. */
  76.    void *mem_ctx;
  77. };
  78.  
  79. } /* namespace */
  80. using namespace opt_array_splitting;
  81.  
  82. /**
  83.  * This class does a walk over the tree, coming up with the set of
  84.  * variables that could be split by looking to see if they are arrays
  85.  * that are only ever constant-index dereferenced.
  86.  */
  87. class ir_array_reference_visitor : public ir_hierarchical_visitor {
  88. public:
  89.    ir_array_reference_visitor(void)
  90.    {
  91.       this->mem_ctx = ralloc_context(NULL);
  92.       this->variable_list.make_empty();
  93.    }
  94.  
  95.    ~ir_array_reference_visitor(void)
  96.    {
  97.       ralloc_free(mem_ctx);
  98.    }
  99.  
  100.    bool get_split_list(exec_list *instructions, bool linked);
  101.  
  102.    virtual ir_visitor_status visit(ir_variable *);
  103.    virtual ir_visitor_status visit(ir_dereference_variable *);
  104.    virtual ir_visitor_status visit_enter(ir_dereference_array *);
  105.    virtual ir_visitor_status visit_enter(ir_function_signature *);
  106.  
  107.    variable_entry *get_variable_entry(ir_variable *var);
  108.  
  109.    /* List of variable_entry */
  110.    exec_list variable_list;
  111.  
  112.    void *mem_ctx;
  113. };
  114.  
  115. variable_entry *
  116. ir_array_reference_visitor::get_variable_entry(ir_variable *var)
  117. {
  118.    assert(var);
  119.  
  120.    if (var->mode != ir_var_auto &&
  121.        var->mode != ir_var_temporary)
  122.       return NULL;
  123.  
  124.    if (!(var->type->is_array() || var->type->is_matrix()))
  125.       return NULL;
  126.  
  127.    /* If the array hasn't been sized yet, we can't split it.  After
  128.     * linking, this should be resolved.
  129.     */
  130.    if (var->type->is_array() && var->type->length == 0)
  131.       return NULL;
  132.  
  133.    foreach_iter(exec_list_iterator, iter, this->variable_list) {
  134.       variable_entry *entry = (variable_entry *)iter.get();
  135.       if (entry->var == var)
  136.          return entry;
  137.    }
  138.  
  139.    variable_entry *entry = new(mem_ctx) variable_entry(var);
  140.    this->variable_list.push_tail(entry);
  141.    return entry;
  142. }
  143.  
  144.  
  145. ir_visitor_status
  146. ir_array_reference_visitor::visit(ir_variable *ir)
  147. {
  148.    variable_entry *entry = this->get_variable_entry(ir);
  149.  
  150.    if (entry)
  151.       entry->declaration = true;
  152.  
  153.    return visit_continue;
  154. }
  155.  
  156. ir_visitor_status
  157. ir_array_reference_visitor::visit(ir_dereference_variable *ir)
  158. {
  159.    variable_entry *entry = this->get_variable_entry(ir->var);
  160.  
  161.    /* If we made it to here without seeing an ir_dereference_array,
  162.     * then the dereference of this array didn't have a constant index
  163.     * (see the visit_continue_with_parent below), so we can't split
  164.     * the variable.
  165.     */
  166.    if (entry)
  167.       entry->split = false;
  168.  
  169.    return visit_continue;
  170. }
  171.  
  172. ir_visitor_status
  173. ir_array_reference_visitor::visit_enter(ir_dereference_array *ir)
  174. {
  175.    ir_dereference_variable *deref = ir->array->as_dereference_variable();
  176.    if (!deref)
  177.       return visit_continue;
  178.  
  179.    variable_entry *entry = this->get_variable_entry(deref->var);
  180.  
  181.    /* If the access to the array has a variable index, we wouldn't
  182.     * know which split variable this dereference should go to.
  183.     */
  184.    if (entry && !ir->array_index->as_constant())
  185.       entry->split = false;
  186.  
  187.    return visit_continue_with_parent;
  188. }
  189.  
  190. ir_visitor_status
  191. ir_array_reference_visitor::visit_enter(ir_function_signature *ir)
  192. {
  193.    /* We don't have logic for array-splitting function arguments,
  194.     * so just look at the body instructions and not the parameter
  195.     * declarations.
  196.     */
  197.    visit_list_elements(this, &ir->body);
  198.    return visit_continue_with_parent;
  199. }
  200.  
  201. bool
  202. ir_array_reference_visitor::get_split_list(exec_list *instructions,
  203.                                            bool linked)
  204. {
  205.    visit_list_elements(this, instructions);
  206.  
  207.    /* If the shaders aren't linked yet, we can't mess with global
  208.     * declarations, which need to be matched by name across shaders.
  209.     */
  210.    if (!linked) {
  211.       foreach_list(node, instructions) {
  212.          ir_variable *var = ((ir_instruction *)node)->as_variable();
  213.          if (var) {
  214.             variable_entry *entry = get_variable_entry(var);
  215.             if (entry)
  216.                entry->remove();
  217.          }
  218.       }
  219.    }
  220.  
  221.    /* Trim out variables we found that we can't split. */
  222.    foreach_iter(exec_list_iterator, iter, variable_list) {
  223.       variable_entry *entry = (variable_entry *)iter.get();
  224.  
  225.       if (debug) {
  226.          printf("array %s@%p: decl %d, split %d\n",
  227.                 entry->var->name, (void *) entry->var, entry->declaration,
  228.                 entry->split);
  229.       }
  230.  
  231.       if (!(entry->declaration && entry->split)) {
  232.          entry->remove();
  233.       }
  234.    }
  235.  
  236.    return !variable_list.is_empty();
  237. }
  238.  
  239. /**
  240.  * This class rewrites the dereferences of arrays that have been split
  241.  * to use the newly created ir_variables for each component.
  242.  */
  243. class ir_array_splitting_visitor : public ir_rvalue_visitor {
  244. public:
  245.    ir_array_splitting_visitor(exec_list *vars)
  246.    {
  247.       this->variable_list = vars;
  248.    }
  249.  
  250.    virtual ~ir_array_splitting_visitor()
  251.    {
  252.    }
  253.  
  254.    virtual ir_visitor_status visit_leave(ir_assignment *);
  255.  
  256.    void split_deref(ir_dereference **deref);
  257.    void handle_rvalue(ir_rvalue **rvalue);
  258.    variable_entry *get_splitting_entry(ir_variable *var);
  259.  
  260.    exec_list *variable_list;
  261. };
  262.  
  263. variable_entry *
  264. ir_array_splitting_visitor::get_splitting_entry(ir_variable *var)
  265. {
  266.    assert(var);
  267.  
  268.    foreach_iter(exec_list_iterator, iter, *this->variable_list) {
  269.       variable_entry *entry = (variable_entry *)iter.get();
  270.       if (entry->var == var) {
  271.          return entry;
  272.       }
  273.    }
  274.  
  275.    return NULL;
  276. }
  277.  
  278. void
  279. ir_array_splitting_visitor::split_deref(ir_dereference **deref)
  280. {
  281.    ir_dereference_array *deref_array = (*deref)->as_dereference_array();
  282.    if (!deref_array)
  283.       return;
  284.  
  285.    ir_dereference_variable *deref_var = deref_array->array->as_dereference_variable();
  286.    if (!deref_var)
  287.       return;
  288.    ir_variable *var = deref_var->var;
  289.  
  290.    variable_entry *entry = get_splitting_entry(var);
  291.    if (!entry)
  292.       return;
  293.  
  294.    ir_constant *constant = deref_array->array_index->as_constant();
  295.    assert(constant);
  296.  
  297.    if (constant->value.i[0] < (int)entry->size) {
  298.       *deref = new(entry->mem_ctx)
  299.          ir_dereference_variable(entry->components[constant->value.i[0]]);
  300.    } else {
  301.       /* There was a constant array access beyond the end of the
  302.        * array.  This might have happened due to constant folding
  303.        * after the initial parse.  This produces an undefined value,
  304.        * but shouldn't crash.  Just give them an uninitialized
  305.        * variable.
  306.        */
  307.       ir_variable *temp = new(entry->mem_ctx) ir_variable(deref_array->type,
  308.                                                           "undef",
  309.                                                           ir_var_temporary);
  310.       entry->components[0]->insert_before(temp);
  311.       *deref = new(entry->mem_ctx) ir_dereference_variable(temp);
  312.    }
  313. }
  314.  
  315. void
  316. ir_array_splitting_visitor::handle_rvalue(ir_rvalue **rvalue)
  317. {
  318.    if (!*rvalue)
  319.       return;
  320.  
  321.    ir_dereference *deref = (*rvalue)->as_dereference();
  322.  
  323.    if (!deref)
  324.       return;
  325.  
  326.    split_deref(&deref);
  327.    *rvalue = deref;
  328. }
  329.  
  330. ir_visitor_status
  331. ir_array_splitting_visitor::visit_leave(ir_assignment *ir)
  332. {
  333.    /* The normal rvalue visitor skips the LHS of assignments, but we
  334.     * need to process those just the same.
  335.     */
  336.    ir_rvalue *lhs = ir->lhs;
  337.  
  338.    handle_rvalue(&lhs);
  339.    ir->lhs = lhs->as_dereference();
  340.  
  341.    ir->lhs->accept(this);
  342.  
  343.    handle_rvalue(&ir->rhs);
  344.    ir->rhs->accept(this);
  345.  
  346.    if (ir->condition) {
  347.       handle_rvalue(&ir->condition);
  348.       ir->condition->accept(this);
  349.    }
  350.  
  351.    return visit_continue;
  352. }
  353.  
  354. bool
  355. optimize_split_arrays(exec_list *instructions, bool linked)
  356. {
  357.    ir_array_reference_visitor refs;
  358.    if (!refs.get_split_list(instructions, linked))
  359.       return false;
  360.  
  361.    void *mem_ctx = ralloc_context(NULL);
  362.  
  363.    /* Replace the decls of the arrays to be split with their split
  364.     * components.
  365.     */
  366.    foreach_iter(exec_list_iterator, iter, refs.variable_list) {
  367.       variable_entry *entry = (variable_entry *)iter.get();
  368.       const struct glsl_type *type = entry->var->type;
  369.       const struct glsl_type *subtype;
  370.  
  371.       if (type->is_matrix())
  372.          subtype = type->column_type();
  373.       else
  374.          subtype = type->fields.array;
  375.  
  376.       entry->mem_ctx = ralloc_parent(entry->var);
  377.  
  378.       entry->components = ralloc_array(mem_ctx,
  379.                                        ir_variable *,
  380.                                        entry->size);
  381.  
  382.       for (unsigned int i = 0; i < entry->size; i++) {
  383.          const char *name = ralloc_asprintf(mem_ctx, "%s_%d",
  384.                                             entry->var->name, i);
  385.  
  386.          entry->components[i] =
  387.             new(entry->mem_ctx) ir_variable(subtype, name, ir_var_temporary);
  388.          entry->var->insert_before(entry->components[i]);
  389.       }
  390.  
  391.       entry->var->remove();
  392.    }
  393.  
  394.    ir_array_splitting_visitor split(&refs.variable_list);
  395.    visit_list_elements(&split, instructions);
  396.  
  397.    if (debug)
  398.       _mesa_print_ir(instructions, NULL);
  399.  
  400.    ralloc_free(mem_ctx);
  401.  
  402.    return true;
  403.  
  404. }
  405.