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