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