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_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.    foreach_two_lists(formal_node, &ir->callee->parameters,
  136.                      actual_node, &ir->actual_parameters) {
  137.       ir_rvalue *param_rval = (ir_rvalue *) actual_node;
  138.       ir_variable *param = (ir_variable *) formal_node;
  139.  
  140.       if (param->data.mode == ir_var_function_out ||
  141.           param->data.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.    }
  150.  
  151.    /* Mark the return storage as having been assigned to */
  152.    if (ir->return_deref != NULL) {
  153.       ir_variable *var = ir->return_deref->variable_referenced();
  154.       struct assignment_entry *entry;
  155.  
  156.       assert(var);
  157.       entry = get_assignment_entry(var, &this->list);
  158.       entry->assignment_count++;
  159.    }
  160.  
  161.    return visit_continue;
  162. }
  163.  
  164. /**
  165.  * Does a copy propagation pass on the code present in the instruction stream.
  166.  */
  167. bool
  168. do_constant_variable(exec_list *instructions)
  169. {
  170.    bool progress = false;
  171.    ir_constant_variable_visitor v;
  172.  
  173.    v.run(instructions);
  174.  
  175.    while (!v.list.is_empty()) {
  176.  
  177.       struct assignment_entry *entry;
  178.       entry = exec_node_data(struct assignment_entry, v.list.head, link);
  179.  
  180.       if (entry->assignment_count == 1 && entry->constval && entry->our_scope) {
  181.          entry->var->constant_value = entry->constval;
  182.          progress = true;
  183.       }
  184.       entry->link.remove();
  185.       free(entry);
  186.    }
  187.  
  188.    return progress;
  189. }
  190.  
  191. bool
  192. do_constant_variable_unlinked(exec_list *instructions)
  193. {
  194.    bool progress = false;
  195.  
  196.    foreach_in_list(ir_instruction, ir, instructions) {
  197.       ir_function *f = ir->as_function();
  198.       if (f) {
  199.          foreach_in_list(ir_function_signature, sig, &f->signatures) {
  200.             if (do_constant_variable(&sig->body))
  201.                progress = true;
  202.          }
  203.       }
  204.    }
  205.  
  206.    return progress;
  207. }
  208.