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