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_array_splitting.cpp 26 * 27 * If an array is always dereferenced with a constant index, then 28 * split it apart into its elements, making it more amenable to other 29 * optimization passes. 30 * 31 * This skips uniform/varying arrays, which would need careful 32 * handling due to their ir->location fields tying them to the GL API 33 * and other shader stages. 34 */ 35 36 #include "ir.h" 37 #include "ir_visitor.h" 38 #include "ir_rvalue_visitor.h" 39 #include "ir_print_visitor.h" 40 #include "glsl_types.h" 41 42 static bool debug = false; 43 44 namespace opt_array_splitting { 45 46 class variable_entry : public exec_node 47 { 48 public: variable_entry(ir_variable * var)49 variable_entry(ir_variable *var) 50 { 51 this->var = var; 52 this->split = true; 53 this->declaration = false; 54 this->components = NULL; 55 this->mem_ctx = NULL; 56 if (var->type->is_array()) 57 this->size = var->type->length; 58 else 59 this->size = var->type->matrix_columns; 60 } 61 62 ir_variable *var; /* The key: the variable's pointer. */ 63 unsigned size; /* array length or matrix columns */ 64 65 /** Whether this array should be split or not. */ 66 bool split; 67 68 /* If the variable had a decl we can work with in the instruction 69 * stream. We can't do splitting on function arguments, which 70 * don't get this variable set. 71 */ 72 bool declaration; 73 74 ir_variable **components; 75 76 /** ralloc_parent(this->var) -- the shader's talloc context. */ 77 void *mem_ctx; 78 }; 79 80 } /* namespace */ 81 using namespace opt_array_splitting; 82 83 /** 84 * This class does a walk over the tree, coming up with the set of 85 * variables that could be split by looking to see if they are arrays 86 * that are only ever constant-index dereferenced. 87 */ 88 class ir_array_reference_visitor : public ir_hierarchical_visitor { 89 public: ir_array_reference_visitor(void)90 ir_array_reference_visitor(void) 91 { 92 this->mem_ctx = ralloc_context(NULL); 93 this->variable_list.make_empty(); 94 } 95 ~ir_array_reference_visitor(void)96 ~ir_array_reference_visitor(void) 97 { 98 ralloc_free(mem_ctx); 99 } 100 101 bool get_split_list(exec_list *instructions, bool linked); 102 103 virtual ir_visitor_status visit(ir_variable *); 104 virtual ir_visitor_status visit(ir_dereference_variable *); 105 virtual ir_visitor_status visit_enter(ir_dereference_array *); 106 virtual ir_visitor_status visit_enter(ir_function_signature *); 107 108 variable_entry *get_variable_entry(ir_variable *var); 109 110 /* List of variable_entry */ 111 exec_list variable_list; 112 113 void *mem_ctx; 114 }; 115 116 variable_entry * get_variable_entry(ir_variable * var)117 ir_array_reference_visitor::get_variable_entry(ir_variable *var) 118 { 119 assert(var); 120 121 if (var->mode != ir_var_auto && 122 var->mode != ir_var_temporary) 123 return NULL; 124 125 if (!(var->type->is_array() || var->type->is_matrix())) 126 return NULL; 127 128 /* If the array hasn't been sized yet, we can't split it. After 129 * linking, this should be resolved. 130 */ 131 if (var->type->is_array() && var->type->length == 0) 132 return NULL; 133 134 foreach_iter(exec_list_iterator, iter, this->variable_list) { 135 variable_entry *entry = (variable_entry *)iter.get(); 136 if (entry->var == var) 137 return entry; 138 } 139 140 variable_entry *entry = new(mem_ctx) variable_entry(var); 141 this->variable_list.push_tail(entry); 142 return entry; 143 } 144 145 146 ir_visitor_status visit(ir_variable * ir)147 ir_array_reference_visitor::visit(ir_variable *ir) 148 { 149 variable_entry *entry = this->get_variable_entry(ir); 150 151 if (entry) 152 entry->declaration = true; 153 154 return visit_continue; 155 } 156 157 ir_visitor_status visit(ir_dereference_variable * ir)158 ir_array_reference_visitor::visit(ir_dereference_variable *ir) 159 { 160 variable_entry *entry = this->get_variable_entry(ir->var); 161 162 /* If we made it to here without seeing an ir_dereference_array, 163 * then the dereference of this array didn't have a constant index 164 * (see the visit_continue_with_parent below), so we can't split 165 * the variable. 166 */ 167 if (entry) 168 entry->split = false; 169 170 return visit_continue; 171 } 172 173 ir_visitor_status visit_enter(ir_dereference_array * ir)174 ir_array_reference_visitor::visit_enter(ir_dereference_array *ir) 175 { 176 ir_dereference_variable *deref = ir->array->as_dereference_variable(); 177 if (!deref) 178 return visit_continue; 179 180 variable_entry *entry = this->get_variable_entry(deref->var); 181 182 /* If the access to the array has a variable index, we wouldn't 183 * know which split variable this dereference should go to. 184 */ 185 if (entry && !ir->array_index->as_constant()) 186 entry->split = false; 187 188 return visit_continue_with_parent; 189 } 190 191 ir_visitor_status visit_enter(ir_function_signature * ir)192 ir_array_reference_visitor::visit_enter(ir_function_signature *ir) 193 { 194 /* We don't have logic for array-splitting function arguments, 195 * so just look at the body instructions and not the parameter 196 * declarations. 197 */ 198 visit_list_elements(this, &ir->body); 199 return visit_continue_with_parent; 200 } 201 202 bool get_split_list(exec_list * instructions,bool linked)203 ir_array_reference_visitor::get_split_list(exec_list *instructions, 204 bool linked) 205 { 206 visit_list_elements(this, instructions); 207 208 /* If the shaders aren't linked yet, we can't mess with global 209 * declarations, which need to be matched by name across shaders. 210 */ 211 if (!linked) { 212 foreach_list(node, instructions) { 213 ir_variable *var = ((ir_instruction *)node)->as_variable(); 214 if (var) { 215 variable_entry *entry = get_variable_entry(var); 216 if (entry) 217 entry->remove(); 218 } 219 } 220 } 221 222 /* Trim out variables we found that we can't split. */ 223 foreach_iter(exec_list_iterator, iter, variable_list) { 224 variable_entry *entry = (variable_entry *)iter.get(); 225 226 if (debug) { 227 printf("array %s@%p: decl %d, split %d\n", 228 entry->var->name, (void *) entry->var, entry->declaration, 229 entry->split); 230 } 231 232 if (!(entry->declaration && entry->split)) { 233 entry->remove(); 234 } 235 } 236 237 return !variable_list.is_empty(); 238 } 239 240 /** 241 * This class rewrites the dereferences of arrays that have been split 242 * to use the newly created ir_variables for each component. 243 */ 244 class ir_array_splitting_visitor : public ir_rvalue_visitor { 245 public: ir_array_splitting_visitor(exec_list * vars)246 ir_array_splitting_visitor(exec_list *vars) 247 { 248 this->variable_list = vars; 249 } 250 ~ir_array_splitting_visitor()251 virtual ~ir_array_splitting_visitor() 252 { 253 } 254 255 virtual ir_visitor_status visit_leave(ir_assignment *); 256 257 void split_deref(ir_dereference **deref); 258 void handle_rvalue(ir_rvalue **rvalue); 259 variable_entry *get_splitting_entry(ir_variable *var); 260 261 exec_list *variable_list; 262 }; 263 264 variable_entry * get_splitting_entry(ir_variable * var)265 ir_array_splitting_visitor::get_splitting_entry(ir_variable *var) 266 { 267 assert(var); 268 269 foreach_iter(exec_list_iterator, iter, *this->variable_list) { 270 variable_entry *entry = (variable_entry *)iter.get(); 271 if (entry->var == var) { 272 return entry; 273 } 274 } 275 276 return NULL; 277 } 278 279 void split_deref(ir_dereference ** deref)280 ir_array_splitting_visitor::split_deref(ir_dereference **deref) 281 { 282 ir_dereference_array *deref_array = (*deref)->as_dereference_array(); 283 if (!deref_array) 284 return; 285 286 ir_dereference_variable *deref_var = deref_array->array->as_dereference_variable(); 287 if (!deref_var) 288 return; 289 ir_variable *var = deref_var->var; 290 291 variable_entry *entry = get_splitting_entry(var); 292 if (!entry) 293 return; 294 295 ir_constant *constant = deref_array->array_index->as_constant(); 296 assert(constant); 297 298 if (constant->value.i[0] < (int)entry->size) { 299 *deref = new(entry->mem_ctx) 300 ir_dereference_variable(entry->components[constant->value.i[0]]); 301 } else { 302 /* There was a constant array access beyond the end of the 303 * array. This might have happened due to constant folding 304 * after the initial parse. This produces an undefined value, 305 * but shouldn't crash. Just give them an uninitialized 306 * variable. 307 */ 308 ir_variable *temp = new(entry->mem_ctx) ir_variable(deref_array->type, 309 "undef", 310 ir_var_temporary); 311 entry->components[0]->insert_before(temp); 312 *deref = new(entry->mem_ctx) ir_dereference_variable(temp); 313 } 314 } 315 316 void handle_rvalue(ir_rvalue ** rvalue)317 ir_array_splitting_visitor::handle_rvalue(ir_rvalue **rvalue) 318 { 319 if (!*rvalue) 320 return; 321 322 ir_dereference *deref = (*rvalue)->as_dereference(); 323 324 if (!deref) 325 return; 326 327 split_deref(&deref); 328 *rvalue = deref; 329 } 330 331 ir_visitor_status visit_leave(ir_assignment * ir)332 ir_array_splitting_visitor::visit_leave(ir_assignment *ir) 333 { 334 /* The normal rvalue visitor skips the LHS of assignments, but we 335 * need to process those just the same. 336 */ 337 ir_rvalue *lhs = ir->lhs; 338 339 handle_rvalue(&lhs); 340 ir->lhs = lhs->as_dereference(); 341 342 ir->lhs->accept(this); 343 344 handle_rvalue(&ir->rhs); 345 ir->rhs->accept(this); 346 347 if (ir->condition) { 348 handle_rvalue(&ir->condition); 349 ir->condition->accept(this); 350 } 351 352 return visit_continue; 353 } 354 355 bool optimize_split_arrays(exec_list * instructions,bool linked)356 optimize_split_arrays(exec_list *instructions, bool linked) 357 { 358 ir_array_reference_visitor refs; 359 if (!refs.get_split_list(instructions, linked)) 360 return false; 361 362 void *mem_ctx = ralloc_context(NULL); 363 364 /* Replace the decls of the arrays to be split with their split 365 * components. 366 */ 367 foreach_iter(exec_list_iterator, iter, refs.variable_list) { 368 variable_entry *entry = (variable_entry *)iter.get(); 369 const struct glsl_type *type = entry->var->type; 370 const struct glsl_type *subtype; 371 372 if (type->is_matrix()) 373 subtype = type->column_type(); 374 else 375 subtype = type->fields.array; 376 377 entry->mem_ctx = ralloc_parent(entry->var); 378 379 entry->components = ralloc_array(mem_ctx, 380 ir_variable *, 381 entry->size); 382 383 for (unsigned int i = 0; i < entry->size; i++) { 384 const char *name = ralloc_asprintf(mem_ctx, "%s_%d", 385 entry->var->name, i); 386 387 entry->components[i] = 388 new(entry->mem_ctx) ir_variable(subtype, name, ir_var_temporary); 389 entry->var->insert_before(entry->components[i]); 390 } 391 392 entry->var->remove(); 393 } 394 395 ir_array_splitting_visitor split(&refs.variable_list); 396 visit_list_elements(&split, instructions); 397 398 if (debug) 399 _mesa_print_ir(instructions, NULL); 400 401 ralloc_free(mem_ctx); 402 403 return true; 404 405 } 406