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_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->mode == ir_var_uniform
  107.        || var->mode == ir_var_shader_in || var->mode == ir_var_shader_out)
  108.       return NULL;
  109.  
  110.    foreach_iter(exec_list_iterator, iter, this->variable_list) {
  111.       variable_entry *entry = (variable_entry *)iter.get();
  112.       if (entry->var == var)
  113.          return entry;
  114.    }
  115.  
  116.    variable_entry *entry = new(mem_ctx) variable_entry(var);
  117.    this->variable_list.push_tail(entry);
  118.    return entry;
  119. }
  120.  
  121.  
  122. ir_visitor_status
  123. ir_structure_reference_visitor::visit(ir_variable *ir)
  124. {
  125.    variable_entry *entry = this->get_variable_entry(ir);
  126.  
  127.    if (entry)
  128.       entry->declaration = true;
  129.  
  130.    return visit_continue;
  131. }
  132.  
  133. ir_visitor_status
  134. ir_structure_reference_visitor::visit(ir_dereference_variable *ir)
  135. {
  136.    ir_variable *const var = ir->variable_referenced();
  137.    variable_entry *entry = this->get_variable_entry(var);
  138.  
  139.    if (entry)
  140.       entry->whole_structure_access++;
  141.  
  142.    return visit_continue;
  143. }
  144.  
  145. ir_visitor_status
  146. ir_structure_reference_visitor::visit_enter(ir_dereference_record *ir)
  147. {
  148.    (void) ir;
  149.    /* Don't descend into the ir_dereference_variable below. */
  150.    return visit_continue_with_parent;
  151. }
  152.  
  153. ir_visitor_status
  154. ir_structure_reference_visitor::visit_enter(ir_assignment *ir)
  155. {
  156.    /* If there are no structure references yet, no need to bother with
  157.     * processing the expression tree.
  158.     */
  159.    if (this->variable_list.is_empty())
  160.       return visit_continue_with_parent;
  161.  
  162.    if (ir->lhs->as_dereference_variable() &&
  163.        ir->rhs->as_dereference_variable() &&
  164.        !ir->condition) {
  165.       /* We'll split copies of a structure to copies of components, so don't
  166.        * descend to the ir_dereference_variables.
  167.        */
  168.       return visit_continue_with_parent;
  169.    }
  170.    return visit_continue;
  171. }
  172.  
  173. ir_visitor_status
  174. ir_structure_reference_visitor::visit_enter(ir_function_signature *ir)
  175. {
  176.    /* We don't have logic for structure-splitting function arguments,
  177.     * so just look at the body instructions and not the parameter
  178.     * declarations.
  179.     */
  180.    visit_list_elements(this, &ir->body);
  181.    return visit_continue_with_parent;
  182. }
  183.  
  184. class ir_structure_splitting_visitor : public ir_rvalue_visitor {
  185. public:
  186.    ir_structure_splitting_visitor(exec_list *vars)
  187.    {
  188.       this->variable_list = vars;
  189.    }
  190.  
  191.    virtual ~ir_structure_splitting_visitor()
  192.    {
  193.    }
  194.  
  195.    virtual ir_visitor_status visit_leave(ir_assignment *);
  196.  
  197.    void split_deref(ir_dereference **deref);
  198.    void handle_rvalue(ir_rvalue **rvalue);
  199.    variable_entry *get_splitting_entry(ir_variable *var);
  200.  
  201.    exec_list *variable_list;
  202. };
  203.  
  204. variable_entry *
  205. ir_structure_splitting_visitor::get_splitting_entry(ir_variable *var)
  206. {
  207.    assert(var);
  208.  
  209.    if (!var->type->is_record())
  210.       return NULL;
  211.  
  212.    foreach_iter(exec_list_iterator, iter, *this->variable_list) {
  213.       variable_entry *entry = (variable_entry *)iter.get();
  214.       if (entry->var == var) {
  215.          return entry;
  216.       }
  217.    }
  218.  
  219.    return NULL;
  220. }
  221.  
  222. void
  223. ir_structure_splitting_visitor::split_deref(ir_dereference **deref)
  224. {
  225.    if ((*deref)->ir_type != ir_type_dereference_record)
  226.       return;
  227.  
  228.    ir_dereference_record *deref_record = (ir_dereference_record *)*deref;
  229.    ir_dereference_variable *deref_var = deref_record->record->as_dereference_variable();
  230.    if (!deref_var)
  231.       return;
  232.  
  233.    variable_entry *entry = get_splitting_entry(deref_var->var);
  234.    if (!entry)
  235.       return;
  236.  
  237.    unsigned int i;
  238.    for (i = 0; i < entry->var->type->length; i++) {
  239.       if (strcmp(deref_record->field,
  240.                  entry->var->type->fields.structure[i].name) == 0)
  241.          break;
  242.    }
  243.    assert(i != entry->var->type->length);
  244.  
  245.    *deref = new(entry->mem_ctx) ir_dereference_variable(entry->components[i]);
  246. }
  247.  
  248. void
  249. ir_structure_splitting_visitor::handle_rvalue(ir_rvalue **rvalue)
  250. {
  251.    if (!*rvalue)
  252.       return;
  253.  
  254.    ir_dereference *deref = (*rvalue)->as_dereference();
  255.  
  256.    if (!deref)
  257.       return;
  258.  
  259.    split_deref(&deref);
  260.    *rvalue = deref;
  261. }
  262.  
  263. ir_visitor_status
  264. ir_structure_splitting_visitor::visit_leave(ir_assignment *ir)
  265. {
  266.    ir_dereference_variable *lhs_deref = ir->lhs->as_dereference_variable();
  267.    ir_dereference_variable *rhs_deref = ir->rhs->as_dereference_variable();
  268.    variable_entry *lhs_entry = lhs_deref ? get_splitting_entry(lhs_deref->var) : NULL;
  269.    variable_entry *rhs_entry = rhs_deref ? get_splitting_entry(rhs_deref->var) : NULL;
  270.    const glsl_type *type = ir->rhs->type;
  271.  
  272.    if ((lhs_entry || rhs_entry) && !ir->condition) {
  273.       for (unsigned int i = 0; i < type->length; i++) {
  274.          ir_dereference *new_lhs, *new_rhs;
  275.          void *mem_ctx = lhs_entry ? lhs_entry->mem_ctx : rhs_entry->mem_ctx;
  276.  
  277.          if (lhs_entry) {
  278.             new_lhs = new(mem_ctx) ir_dereference_variable(lhs_entry->components[i]);
  279.          } else {
  280.             new_lhs = new(mem_ctx)
  281.                ir_dereference_record(ir->lhs->clone(mem_ctx, NULL),
  282.                                      type->fields.structure[i].name);
  283.          }
  284.  
  285.          if (rhs_entry) {
  286.             new_rhs = new(mem_ctx) ir_dereference_variable(rhs_entry->components[i]);
  287.          } else {
  288.             new_rhs = new(mem_ctx)
  289.                ir_dereference_record(ir->rhs->clone(mem_ctx, NULL),
  290.                                      type->fields.structure[i].name);
  291.          }
  292.  
  293.          ir->insert_before(new(mem_ctx) ir_assignment(new_lhs,
  294.                                                       new_rhs,
  295.                                                       NULL));
  296.       }
  297.       ir->remove();
  298.    } else {
  299.       handle_rvalue(&ir->rhs);
  300.       split_deref(&ir->lhs);
  301.    }
  302.  
  303.    handle_rvalue(&ir->condition);
  304.  
  305.    return visit_continue;
  306. }
  307.  
  308. } /* unnamed namespace */
  309.  
  310. bool
  311. do_structure_splitting(exec_list *instructions)
  312. {
  313.    ir_structure_reference_visitor refs;
  314.  
  315.    visit_list_elements(&refs, instructions);
  316.  
  317.    /* Trim out variables we can't split. */
  318.    foreach_iter(exec_list_iterator, iter, refs.variable_list) {
  319.       variable_entry *entry = (variable_entry *)iter.get();
  320.  
  321.       if (debug) {
  322.          printf("structure %s@%p: decl %d, whole_access %d\n",
  323.                 entry->var->name, (void *) entry->var, entry->declaration,
  324.                 entry->whole_structure_access);
  325.       }
  326.  
  327.       if (!entry->declaration || entry->whole_structure_access) {
  328.          entry->remove();
  329.       }
  330.    }
  331.  
  332.    if (refs.variable_list.is_empty())
  333.       return false;
  334.  
  335.    void *mem_ctx = ralloc_context(NULL);
  336.  
  337.    /* Replace the decls of the structures to be split with their split
  338.     * components.
  339.     */
  340.    foreach_iter(exec_list_iterator, iter, refs.variable_list) {
  341.       variable_entry *entry = (variable_entry *)iter.get();
  342.       const struct glsl_type *type = entry->var->type;
  343.  
  344.       entry->mem_ctx = ralloc_parent(entry->var);
  345.  
  346.       entry->components = ralloc_array(mem_ctx,
  347.                                        ir_variable *,
  348.                                        type->length);
  349.  
  350.       for (unsigned int i = 0; i < entry->var->type->length; i++) {
  351.          const char *name = ralloc_asprintf(mem_ctx, "%s_%s",
  352.                                             entry->var->name,
  353.                                             type->fields.structure[i].name);
  354.  
  355.          entry->components[i] =
  356.             new(entry->mem_ctx) ir_variable(type->fields.structure[i].type,
  357.                                             name,
  358.                                             ir_var_temporary);
  359.          entry->var->insert_before(entry->components[i]);
  360.       }
  361.  
  362.       entry->var->remove();
  363.    }
  364.  
  365.    ir_structure_splitting_visitor split(&refs.variable_list);
  366.    visit_list_elements(&split, instructions);
  367.  
  368.    ralloc_free(mem_ctx);
  369.  
  370.    return true;
  371. }
  372.