Subversion Repositories Kolibri OS

Rev

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