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_structure_splitting.cpp
  26.  *
  27.  * If a structure is only ever referenced by its components, then
  28.  * split those components out to individual variables so they can be
  29.  * handled normally by other optimization passes.
  30.  *
  31.  * This skips structures like uniforms, which need to be accessible as
  32.  * structures for their access by the GL.
  33.  */
  34.  
  35. #include "ir.h"
  36. #include "ir_visitor.h"
  37. #include "ir_rvalue_visitor.h"
  38. #include "glsl_types.h"
  39.  
  40. namespace {
  41.  
  42. static bool debug = false;
  43.  
  44. class variable_entry : public exec_node
  45. {
  46. public:
  47.    variable_entry(ir_variable *var)
  48.    {
  49.       this->var = var;
  50.       this->whole_structure_access = 0;
  51.       this->declaration = false;
  52.       this->components = NULL;
  53.       this->mem_ctx = NULL;
  54.    }
  55.  
  56.    ir_variable *var; /* The key: the variable's pointer. */
  57.  
  58.    /** Number of times the variable is referenced, including assignments. */
  59.    unsigned whole_structure_access;
  60.  
  61.    /* If the variable had a decl we can work with in the instruction
  62.     * stream.  We can't do splitting on function arguments, which
  63.     * don't get this variable set.
  64.     */
  65.    bool declaration;
  66.  
  67.    ir_variable **components;
  68.  
  69.    /** ralloc_parent(this->var) -- the shader's ralloc context. */
  70.    void *mem_ctx;
  71. };
  72.  
  73.  
  74. class ir_structure_reference_visitor : public ir_hierarchical_visitor {
  75. public:
  76.    ir_structure_reference_visitor(void)
  77.    {
  78.       this->mem_ctx = ralloc_context(NULL);
  79.       this->variable_list.make_empty();
  80.    }
  81.  
  82.    ~ir_structure_reference_visitor(void)
  83.    {
  84.       ralloc_free(mem_ctx);
  85.    }
  86.  
  87.    virtual ir_visitor_status visit(ir_variable *);
  88.    virtual ir_visitor_status visit(ir_dereference_variable *);
  89.    virtual ir_visitor_status visit_enter(ir_dereference_record *);
  90.    virtual ir_visitor_status visit_enter(ir_assignment *);
  91.    virtual ir_visitor_status visit_enter(ir_function_signature *);
  92.  
  93.    variable_entry *get_variable_entry(ir_variable *var);
  94.  
  95.    /* List of variable_entry */
  96.    exec_list variable_list;
  97.  
  98.    void *mem_ctx;
  99. };
  100.  
  101. variable_entry *
  102. ir_structure_reference_visitor::get_variable_entry(ir_variable *var)
  103. {
  104.    assert(var);
  105.  
  106.    if (!var->type->is_record() || var->data.mode == ir_var_uniform
  107.        || var->data.mode == ir_var_shader_in || var->data.mode == ir_var_shader_out)
  108.       return NULL;
  109.  
  110.    foreach_in_list(variable_entry, entry, &this->variable_list) {
  111.       if (entry->var == var)
  112.          return entry;
  113.    }
  114.  
  115.    variable_entry *entry = new(mem_ctx) variable_entry(var);
  116.    this->variable_list.push_tail(entry);
  117.    return entry;
  118. }
  119.  
  120.  
  121. ir_visitor_status
  122. ir_structure_reference_visitor::visit(ir_variable *ir)
  123. {
  124.    variable_entry *entry = this->get_variable_entry(ir);
  125.  
  126.    if (entry)
  127.       entry->declaration = true;
  128.  
  129.    return visit_continue;
  130. }
  131.  
  132. ir_visitor_status
  133. ir_structure_reference_visitor::visit(ir_dereference_variable *ir)
  134. {
  135.    ir_variable *const var = ir->variable_referenced();
  136.    variable_entry *entry = this->get_variable_entry(var);
  137.  
  138.    if (entry)
  139.       entry->whole_structure_access++;
  140.  
  141.    return visit_continue;
  142. }
  143.  
  144. ir_visitor_status
  145. ir_structure_reference_visitor::visit_enter(ir_dereference_record *ir)
  146. {
  147.    (void) ir;
  148.    /* Don't descend into the ir_dereference_variable below. */
  149.    return visit_continue_with_parent;
  150. }
  151.  
  152. ir_visitor_status
  153. ir_structure_reference_visitor::visit_enter(ir_assignment *ir)
  154. {
  155.    /* If there are no structure references yet, no need to bother with
  156.     * processing the expression tree.
  157.     */
  158.    if (this->variable_list.is_empty())
  159.       return visit_continue_with_parent;
  160.  
  161.    if (ir->lhs->as_dereference_variable() &&
  162.        ir->rhs->as_dereference_variable() &&
  163.        !ir->condition) {
  164.       /* We'll split copies of a structure to copies of components, so don't
  165.        * descend to the ir_dereference_variables.
  166.        */
  167.       return visit_continue_with_parent;
  168.    }
  169.    return visit_continue;
  170. }
  171.  
  172. ir_visitor_status
  173. ir_structure_reference_visitor::visit_enter(ir_function_signature *ir)
  174. {
  175.    /* We don't have logic for structure-splitting function arguments,
  176.     * so just look at the body instructions and not the parameter
  177.     * declarations.
  178.     */
  179.    visit_list_elements(this, &ir->body);
  180.    return visit_continue_with_parent;
  181. }
  182.  
  183. class ir_structure_splitting_visitor : public ir_rvalue_visitor {
  184. public:
  185.    ir_structure_splitting_visitor(exec_list *vars)
  186.    {
  187.       this->variable_list = vars;
  188.    }
  189.  
  190.    virtual ~ir_structure_splitting_visitor()
  191.    {
  192.    }
  193.  
  194.    virtual ir_visitor_status visit_leave(ir_assignment *);
  195.  
  196.    void split_deref(ir_dereference **deref);
  197.    void handle_rvalue(ir_rvalue **rvalue);
  198.    variable_entry *get_splitting_entry(ir_variable *var);
  199.  
  200.    exec_list *variable_list;
  201. };
  202.  
  203. variable_entry *
  204. ir_structure_splitting_visitor::get_splitting_entry(ir_variable *var)
  205. {
  206.    assert(var);
  207.  
  208.    if (!var->type->is_record())
  209.       return NULL;
  210.  
  211.    foreach_in_list(variable_entry, entry, this->variable_list) {
  212.       if (entry->var == var) {
  213.          return entry;
  214.       }
  215.    }
  216.  
  217.    return NULL;
  218. }
  219.  
  220. void
  221. ir_structure_splitting_visitor::split_deref(ir_dereference **deref)
  222. {
  223.    if ((*deref)->ir_type != ir_type_dereference_record)
  224.       return;
  225.  
  226.    ir_dereference_record *deref_record = (ir_dereference_record *)*deref;
  227.    ir_dereference_variable *deref_var = deref_record->record->as_dereference_variable();
  228.    if (!deref_var)
  229.       return;
  230.  
  231.    variable_entry *entry = get_splitting_entry(deref_var->var);
  232.    if (!entry)
  233.       return;
  234.  
  235.    unsigned int i;
  236.    for (i = 0; i < entry->var->type->length; i++) {
  237.       if (strcmp(deref_record->field,
  238.                  entry->var->type->fields.structure[i].name) == 0)
  239.          break;
  240.    }
  241.    assert(i != entry->var->type->length);
  242.  
  243.    *deref = new(entry->mem_ctx) ir_dereference_variable(entry->components[i]);
  244. }
  245.  
  246. void
  247. ir_structure_splitting_visitor::handle_rvalue(ir_rvalue **rvalue)
  248. {
  249.    if (!*rvalue)
  250.       return;
  251.  
  252.    ir_dereference *deref = (*rvalue)->as_dereference();
  253.  
  254.    if (!deref)
  255.       return;
  256.  
  257.    split_deref(&deref);
  258.    *rvalue = deref;
  259. }
  260.  
  261. ir_visitor_status
  262. ir_structure_splitting_visitor::visit_leave(ir_assignment *ir)
  263. {
  264.    ir_dereference_variable *lhs_deref = ir->lhs->as_dereference_variable();
  265.    ir_dereference_variable *rhs_deref = ir->rhs->as_dereference_variable();
  266.    variable_entry *lhs_entry = lhs_deref ? get_splitting_entry(lhs_deref->var) : NULL;
  267.    variable_entry *rhs_entry = rhs_deref ? get_splitting_entry(rhs_deref->var) : NULL;
  268.    const glsl_type *type = ir->rhs->type;
  269.  
  270.    if ((lhs_entry || rhs_entry) && !ir->condition) {
  271.       for (unsigned int i = 0; i < type->length; i++) {
  272.          ir_dereference *new_lhs, *new_rhs;
  273.          void *mem_ctx = lhs_entry ? lhs_entry->mem_ctx : rhs_entry->mem_ctx;
  274.  
  275.          if (lhs_entry) {
  276.             new_lhs = new(mem_ctx) ir_dereference_variable(lhs_entry->components[i]);
  277.          } else {
  278.             new_lhs = new(mem_ctx)
  279.                ir_dereference_record(ir->lhs->clone(mem_ctx, NULL),
  280.                                      type->fields.structure[i].name);
  281.          }
  282.  
  283.          if (rhs_entry) {
  284.             new_rhs = new(mem_ctx) ir_dereference_variable(rhs_entry->components[i]);
  285.          } else {
  286.             new_rhs = new(mem_ctx)
  287.                ir_dereference_record(ir->rhs->clone(mem_ctx, NULL),
  288.                                      type->fields.structure[i].name);
  289.          }
  290.  
  291.          ir->insert_before(new(mem_ctx) ir_assignment(new_lhs,
  292.                                                       new_rhs,
  293.                                                       NULL));
  294.       }
  295.       ir->remove();
  296.    } else {
  297.       handle_rvalue(&ir->rhs);
  298.       split_deref(&ir->lhs);
  299.    }
  300.  
  301.    handle_rvalue(&ir->condition);
  302.  
  303.    return visit_continue;
  304. }
  305.  
  306. } /* unnamed namespace */
  307.  
  308. bool
  309. do_structure_splitting(exec_list *instructions)
  310. {
  311.    ir_structure_reference_visitor refs;
  312.  
  313.    visit_list_elements(&refs, instructions);
  314.  
  315.    /* Trim out variables we can't split. */
  316.    foreach_in_list_safe(variable_entry, entry, &refs.variable_list) {
  317.       if (debug) {
  318.          printf("structure %s@%p: decl %d, whole_access %d\n",
  319.                 entry->var->name, (void *) entry->var, entry->declaration,
  320.                 entry->whole_structure_access);
  321.       }
  322.  
  323.       if (!entry->declaration || entry->whole_structure_access) {
  324.          entry->remove();
  325.       }
  326.    }
  327.  
  328.    if (refs.variable_list.is_empty())
  329.       return false;
  330.  
  331.    void *mem_ctx = ralloc_context(NULL);
  332.  
  333.    /* Replace the decls of the structures to be split with their split
  334.     * components.
  335.     */
  336.    foreach_in_list_safe(variable_entry, entry, &refs.variable_list) {
  337.       const struct glsl_type *type = entry->var->type;
  338.  
  339.       entry->mem_ctx = ralloc_parent(entry->var);
  340.  
  341.       entry->components = ralloc_array(mem_ctx,
  342.                                        ir_variable *,
  343.                                        type->length);
  344.  
  345.       for (unsigned int i = 0; i < entry->var->type->length; i++) {
  346.          const char *name = ralloc_asprintf(mem_ctx, "%s_%s",
  347.                                             entry->var->name,
  348.                                             type->fields.structure[i].name);
  349.  
  350.          entry->components[i] =
  351.             new(entry->mem_ctx) ir_variable(type->fields.structure[i].type,
  352.                                             name,
  353.                                             ir_var_temporary);
  354.          entry->var->insert_before(entry->components[i]);
  355.       }
  356.  
  357.       entry->var->remove();
  358.    }
  359.  
  360.    ir_structure_splitting_visitor split(&refs.variable_list);
  361.    visit_list_elements(&split, instructions);
  362.  
  363.    ralloc_free(mem_ctx);
  364.  
  365.    return true;
  366. }
  367.