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_folding.cpp
  26.  * Replace constant-valued expressions with references to constant values.
  27.  */
  28.  
  29. #include "ir.h"
  30. #include "ir_visitor.h"
  31. #include "ir_rvalue_visitor.h"
  32. #include "ir_optimization.h"
  33. #include "glsl_types.h"
  34.  
  35. namespace {
  36.  
  37. /**
  38.  * Visitor class for replacing expressions with ir_constant values.
  39.  */
  40.  
  41. class ir_constant_folding_visitor : public ir_rvalue_visitor {
  42. public:
  43.    ir_constant_folding_visitor()
  44.    {
  45.       this->progress = false;
  46.    }
  47.  
  48.    virtual ~ir_constant_folding_visitor()
  49.    {
  50.       /* empty */
  51.    }
  52.  
  53.    virtual ir_visitor_status visit_enter(ir_discard *ir);
  54.    virtual ir_visitor_status visit_enter(ir_assignment *ir);
  55.    virtual ir_visitor_status visit_enter(ir_call *ir);
  56.  
  57.    virtual void handle_rvalue(ir_rvalue **rvalue);
  58.  
  59.    bool progress;
  60. };
  61.  
  62. } /* unnamed namespace */
  63.  
  64. void
  65. ir_constant_folding_visitor::handle_rvalue(ir_rvalue **rvalue)
  66. {
  67.    if (*rvalue == NULL || (*rvalue)->ir_type == ir_type_constant)
  68.       return;
  69.  
  70.    /* Note that we do rvalue visitoring on leaving.  So if an
  71.     * expression has a non-constant operand, no need to go looking
  72.     * down it to find if it's constant.  This cuts the time of this
  73.     * pass down drastically.
  74.     */
  75.    ir_expression *expr = (*rvalue)->as_expression();
  76.    if (expr) {
  77.       for (unsigned int i = 0; i < expr->get_num_operands(); i++) {
  78.          if (!expr->operands[i]->as_constant())
  79.             return;
  80.       }
  81.    }
  82.  
  83.    /* Ditto for swizzles. */
  84.    ir_swizzle *swiz = (*rvalue)->as_swizzle();
  85.    if (swiz && !swiz->val->as_constant())
  86.       return;
  87.  
  88.    ir_constant *constant = (*rvalue)->constant_expression_value();
  89.    if (constant) {
  90.       *rvalue = constant;
  91.       this->progress = true;
  92.    } else {
  93.       (*rvalue)->accept(this);
  94.    }
  95. }
  96.  
  97. ir_visitor_status
  98. ir_constant_folding_visitor::visit_enter(ir_discard *ir)
  99. {
  100.    if (ir->condition) {
  101.       ir->condition->accept(this);
  102.       handle_rvalue(&ir->condition);
  103.  
  104.       ir_constant *const_val = ir->condition->as_constant();
  105.       /* If the condition is constant, either remove the condition or
  106.        * remove the never-executed assignment.
  107.        */
  108.       if (const_val) {
  109.          if (const_val->value.b[0])
  110.             ir->condition = NULL;
  111.          else
  112.             ir->remove();
  113.          this->progress = true;
  114.       }
  115.    }
  116.  
  117.    return visit_continue_with_parent;
  118. }
  119.  
  120. ir_visitor_status
  121. ir_constant_folding_visitor::visit_enter(ir_assignment *ir)
  122. {
  123.    ir->rhs->accept(this);
  124.    handle_rvalue(&ir->rhs);
  125.  
  126.    if (ir->condition) {
  127.       ir->condition->accept(this);
  128.       handle_rvalue(&ir->condition);
  129.  
  130.       ir_constant *const_val = ir->condition->as_constant();
  131.       /* If the condition is constant, either remove the condition or
  132.        * remove the never-executed assignment.
  133.        */
  134.       if (const_val) {
  135.          if (const_val->value.b[0])
  136.             ir->condition = NULL;
  137.          else
  138.             ir->remove();
  139.          this->progress = true;
  140.       }
  141.    }
  142.  
  143.    /* Don't descend into the LHS because we want it to stay as a
  144.     * variable dereference.  FINISHME: We probably should to get array
  145.     * indices though.
  146.     */
  147.    return visit_continue_with_parent;
  148. }
  149.  
  150. ir_visitor_status
  151. ir_constant_folding_visitor::visit_enter(ir_call *ir)
  152. {
  153.    /* Attempt to constant fold parameters */
  154.    foreach_two_lists(formal_node, &ir->callee->parameters,
  155.                      actual_node, &ir->actual_parameters) {
  156.       ir_rvalue *param_rval = (ir_rvalue *) actual_node;
  157.       ir_variable *sig_param = (ir_variable *) formal_node;
  158.  
  159.       if (sig_param->data.mode == ir_var_function_in
  160.           || sig_param->data.mode == ir_var_const_in) {
  161.          ir_rvalue *new_param = param_rval;
  162.  
  163.          handle_rvalue(&new_param);
  164.          if (new_param != param_rval) {
  165.             param_rval->replace_with(new_param);
  166.          }
  167.       }
  168.    }
  169.  
  170.    /* Next, see if the call can be replaced with an assignment of a constant */
  171.    ir_constant *const_val = ir->constant_expression_value();
  172.  
  173.    if (const_val != NULL) {
  174.       ir_assignment *assignment =
  175.          new(ralloc_parent(ir)) ir_assignment(ir->return_deref, const_val);
  176.       ir->replace_with(assignment);
  177.    }
  178.  
  179.    return visit_continue_with_parent;
  180. }
  181.  
  182. bool
  183. do_constant_folding(exec_list *instructions)
  184. {
  185.    ir_constant_folding_visitor constant_folding;
  186.  
  187.    visit_list_elements(&constant_folding, instructions);
  188.  
  189.    return constant_folding.progress;
  190. }
  191.