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/** 36 * Visitor class for replacing expressions with ir_constant values. 37 */ 38 39class ir_constant_folding_visitor : public ir_rvalue_visitor { 40public: 41 ir_constant_folding_visitor() 42 { 43 this->progress = false; 44 } 45 46 virtual ~ir_constant_folding_visitor() 47 { 48 /* empty */ 49 } 50 51 virtual ir_visitor_status visit_enter(ir_assignment *ir); 52 virtual ir_visitor_status visit_enter(ir_call *ir); 53 54 virtual void handle_rvalue(ir_rvalue **rvalue); 55 56 bool progress; 57}; 58 59void 60ir_constant_folding_visitor::handle_rvalue(ir_rvalue **rvalue) 61{ 62 if (*rvalue == NULL || (*rvalue)->ir_type == ir_type_constant) 63 return; 64 65 /* Note that we do rvalue visitoring on leaving. So if an 66 * expression has a non-constant operand, no need to go looking 67 * down it to find if it's constant. This cuts the time of this 68 * pass down drastically. 69 */ 70 ir_expression *expr = (*rvalue)->as_expression(); 71 if (expr) { 72 for (unsigned int i = 0; i < expr->get_num_operands(); i++) { 73 if (!expr->operands[i]->as_constant()) 74 return; 75 } 76 } 77 78 ir_constant *constant = (*rvalue)->constant_expression_value(); 79 if (constant) { 80 *rvalue = constant; 81 this->progress = true; 82 } else { 83 (*rvalue)->accept(this); 84 } 85} 86 87ir_visitor_status 88ir_constant_folding_visitor::visit_enter(ir_assignment *ir) 89{ 90 ir->rhs->accept(this); 91 handle_rvalue(&ir->rhs); 92 93 if (ir->condition) { 94 ir->condition->accept(this); 95 handle_rvalue(&ir->condition); 96 97 ir_constant *const_val = ir->condition->as_constant(); 98 /* If the condition is constant, either remove the condition or 99 * remove the never-executed assignment. 100 */ 101 if (const_val) { 102 if (const_val->value.b[0]) 103 ir->condition = NULL; 104 else 105 ir->remove(); 106 this->progress = true; 107 } 108 } 109 110 /* Don't descend into the LHS because we want it to stay as a 111 * variable dereference. FINISHME: We probably should to get array 112 * indices though. 113 */ 114 return visit_continue_with_parent; 115} 116 117ir_visitor_status 118ir_constant_folding_visitor::visit_enter(ir_call *ir) 119{ 120 exec_list_iterator sig_iter = ir->get_callee()->parameters.iterator(); 121 foreach_iter(exec_list_iterator, iter, *ir) { 122 ir_rvalue *param_rval = (ir_rvalue *)iter.get(); 123 ir_variable *sig_param = (ir_variable *)sig_iter.get(); 124 125 if (sig_param->mode == ir_var_in) { 126 ir_rvalue *new_param = param_rval; 127 128 handle_rvalue(&new_param); 129 if (new_param != param_rval) { 130 param_rval->replace_with(new_param); 131 } 132 } 133 sig_iter.next(); 134 } 135 136 return visit_continue_with_parent; 137} 138 139bool 140do_constant_folding(exec_list *instructions) 141{ 142 ir_constant_folding_visitor constant_folding; 143 144 visit_list_elements(&constant_folding, instructions); 145 146 return constant_folding.progress; 147} 148