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_constant_variable.cpp
  26.  *
  27.  * Marks variables assigned a single constant value over the course
  28.  * of the program as constant.
  29.  *
  30.  * The goal here is to trigger further constant folding and then dead
  31.  * code elimination.  This is common with vector/matrix constructors
  32.  * and calls to builtin functions.
  33.  */
  34.  
  35. #include "ir.h"
  36. #include "ir_visitor.h"
  37. #include "ir_optimization.h"
  38. #include "glsl_types.h"
  39.  
  40. namespace {
  41.  
  42. struct assignment_entry {
  43.    exec_node link;
  44.    int assignment_count;
  45.    ir_variable *var;
  46.    ir_constant *constval;
  47.    bool our_scope;
  48. };
  49.  
  50. class ir_constant_variable_visitor : public ir_hierarchical_visitor {
  51. public:
  52.    virtual ir_visitor_status visit_enter(ir_dereference_variable *);
  53.    virtual ir_visitor_status visit(ir_variable *);
  54.    virtual ir_visitor_status visit_enter(ir_assignment *);
  55.    virtual ir_visitor_status visit_enter(ir_call *);
  56.  
  57.    exec_list list;
  58. };
  59.  
  60. } /* unnamed namespace */
  61.  
  62. static struct assignment_entry *
  63. get_assignment_entry(ir_variable *var, exec_list *list)
  64. {
  65.    struct assignment_entry *entry;
  66.  
  67.    foreach_list_typed(struct assignment_entry, entry, link, list) {
  68.       if (entry->var == var)
  69.          return entry;
  70.    }
  71.  
  72.    entry = (struct assignment_entry *)calloc(1, sizeof(*entry));
  73.    entry->var = var;
  74.    list->push_head(&entry->link);
  75.    return entry;
  76. }
  77.  
  78. ir_visitor_status
  79. ir_constant_variable_visitor::visit(ir_variable *ir)
  80. {
  81.    struct assignment_entry *entry = get_assignment_entry(ir, &this->list);
  82.    entry->our_scope = true;
  83.    return visit_continue;
  84. }
  85.  
  86. /* Skip derefs of variables so that we can detect declarations. */
  87. ir_visitor_status
  88. ir_constant_variable_visitor::visit_enter(ir_dereference_variable *ir)
  89. {
  90.    (void)ir;
  91.    return visit_continue_with_parent;
  92. }
  93.  
  94. ir_visitor_status
  95. ir_constant_variable_visitor::visit_enter(ir_assignment *ir)
  96. {
  97.    ir_constant *constval;
  98.    struct assignment_entry *entry;
  99.  
  100.    entry = get_assignment_entry(ir->lhs->variable_referenced(), &this->list);
  101.    assert(entry);
  102.    entry->assignment_count++;
  103.  
  104.    /* If it's already constant, don't do the work. */
  105.    if (entry->var->constant_value)
  106.       return visit_continue;
  107.  
  108.    /* OK, now find if we actually have all the right conditions for
  109.     * this to be a constant value assigned to the var.
  110.     */
  111.    if (ir->condition)
  112.       return visit_continue;
  113.  
  114.    ir_variable *var = ir->whole_variable_written();
  115.    if (!var)
  116.       return visit_continue;
  117.  
  118.    constval = ir->rhs->constant_expression_value();
  119.    if (!constval)
  120.       return visit_continue;
  121.  
  122.    /* Mark this entry as having a constant assignment (if the
  123.     * assignment count doesn't go >1).  do_constant_variable will fix
  124.     * up the variable with the constant value later.
  125.     */
  126.    entry->constval = constval;
  127.  
  128.    return visit_continue;
  129. }
  130.  
  131. ir_visitor_status
  132. ir_constant_variable_visitor::visit_enter(ir_call *ir)
  133. {
  134.    /* Mark any out parameters as assigned to */
  135.    exec_list_iterator sig_iter = ir->callee->parameters.iterator();
  136.    foreach_iter(exec_list_iterator, iter, *ir) {
  137.       ir_rvalue *param_rval = (ir_rvalue *)iter.get();
  138.       ir_variable *param = (ir_variable *)sig_iter.get();
  139.  
  140.       if (param->mode == ir_var_function_out ||
  141.           param->mode == ir_var_function_inout) {
  142.          ir_variable *var = param_rval->variable_referenced();
  143.          struct assignment_entry *entry;
  144.  
  145.          assert(var);
  146.          entry = get_assignment_entry(var, &this->list);
  147.          entry->assignment_count++;
  148.       }
  149.       sig_iter.next();
  150.    }
  151.  
  152.    /* Mark the return storage as having been assigned to */
  153.    if (ir->return_deref != NULL) {
  154.       ir_variable *var = ir->return_deref->variable_referenced();
  155.       struct assignment_entry *entry;
  156.  
  157.       assert(var);
  158.       entry = get_assignment_entry(var, &this->list);
  159.       entry->assignment_count++;
  160.    }
  161.  
  162.    return visit_continue;
  163. }
  164.  
  165. /**
  166.  * Does a copy propagation pass on the code present in the instruction stream.
  167.  */
  168. bool
  169. do_constant_variable(exec_list *instructions)
  170. {
  171.    bool progress = false;
  172.    ir_constant_variable_visitor v;
  173.  
  174.    v.run(instructions);
  175.  
  176.    while (!v.list.is_empty()) {
  177.  
  178.       struct assignment_entry *entry;
  179.       entry = exec_node_data(struct assignment_entry, v.list.head, link);
  180.  
  181.       if (entry->assignment_count == 1 && entry->constval && entry->our_scope) {
  182.          entry->var->constant_value = entry->constval;
  183.          progress = true;
  184.       }
  185.       entry->link.remove();
  186.       free(entry);
  187.    }
  188.  
  189.    return progress;
  190. }
  191.  
  192. bool
  193. do_constant_variable_unlinked(exec_list *instructions)
  194. {
  195.    bool progress = false;
  196.  
  197.    foreach_iter(exec_list_iterator, iter, *instructions) {
  198.       ir_instruction *ir = (ir_instruction *)iter.get();
  199.       ir_function *f = ir->as_function();
  200.       if (f) {
  201.          foreach_iter(exec_list_iterator, sigiter, *f) {
  202.             ir_function_signature *sig =
  203.                (ir_function_signature *) sigiter.get();
  204.             if (do_constant_variable(&sig->body))
  205.                progress = true;
  206.          }
  207.       }
  208.    }
  209.  
  210.    return progress;
  211. }
  212.