opt_structure_splitting.cpp revision 32aaf89823de11e98cb59d5ec78c66cd3e74bcd4
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 ir_structure_splitting.cpp 26 * 27 * If a structure is only ever referenced by its components, then 28 * split those components out to individual variables so they can be 29 * handled normally by other optimization passes. 30 * 31 * This skips structures like uniforms, which need to be accessible as 32 * structures for their access by the GL. 33 */ 34 35#include "ir.h" 36#include "ir_visitor.h" 37#include "ir_print_visitor.h" 38#include "ir_rvalue_visitor.h" 39#include "glsl_types.h" 40 41static bool debug = false; 42 43// XXX using variable_entry2 here to avoid collision (MSVC multiply-defined 44// function) with the variable_entry class seen in ir_variable_refcount.h 45// Perhaps we can use the one in ir_variable_refcount.h and make this class 46// here go away? 47class variable_entry2 : public exec_node 48{ 49public: 50 variable_entry2(ir_variable *var) 51 { 52 this->var = var; 53 this->whole_structure_access = 0; 54 this->declaration = false; 55 this->components = NULL; 56 this->mem_ctx = NULL; 57 } 58 59 ir_variable *var; /* The key: the variable's pointer. */ 60 61 /** Number of times the variable is referenced, including assignments. */ 62 unsigned whole_structure_access; 63 64 bool declaration; /* If the variable had a decl in the instruction stream */ 65 66 ir_variable **components; 67 68 /** talloc_parent(this->var) -- the shader's talloc context. */ 69 void *mem_ctx; 70}; 71 72 73class ir_structure_reference_visitor : public ir_hierarchical_visitor { 74public: 75 ir_structure_reference_visitor(void) 76 { 77 this->mem_ctx = talloc_new(NULL); 78 this->variable_list.make_empty(); 79 } 80 81 ~ir_structure_reference_visitor(void) 82 { 83 talloc_free(mem_ctx); 84 } 85 86 virtual ir_visitor_status visit(ir_variable *); 87 virtual ir_visitor_status visit(ir_dereference_variable *); 88 virtual ir_visitor_status visit_enter(ir_dereference_record *); 89 virtual ir_visitor_status visit_enter(ir_assignment *); 90 virtual ir_visitor_status visit_enter(ir_function_signature *); 91 92 variable_entry2 *get_variable_entry2(ir_variable *var); 93 94 /* List of variable_entry */ 95 exec_list variable_list; 96 97 void *mem_ctx; 98}; 99 100variable_entry2 * 101ir_structure_reference_visitor::get_variable_entry2(ir_variable *var) 102{ 103 assert(var); 104 105 if (!var->type->is_record() || var->mode == ir_var_uniform) 106 return NULL; 107 108 foreach_iter(exec_list_iterator, iter, this->variable_list) { 109 variable_entry2 *entry = (variable_entry2 *)iter.get(); 110 if (entry->var == var) 111 return entry; 112 } 113 114 variable_entry2 *entry = new(mem_ctx) variable_entry2(var); 115 this->variable_list.push_tail(entry); 116 return entry; 117} 118 119 120ir_visitor_status 121ir_structure_reference_visitor::visit(ir_variable *ir) 122{ 123 variable_entry2 *entry = this->get_variable_entry2(ir); 124 125 if (entry) 126 entry->declaration = true; 127 128 return visit_continue; 129} 130 131ir_visitor_status 132ir_structure_reference_visitor::visit(ir_dereference_variable *ir) 133{ 134 ir_variable *const var = ir->variable_referenced(); 135 variable_entry2 *entry = this->get_variable_entry2(var); 136 137 if (entry) 138 entry->whole_structure_access++; 139 140 return visit_continue; 141} 142 143ir_visitor_status 144ir_structure_reference_visitor::visit_enter(ir_dereference_record *ir) 145{ 146 (void) ir; 147 /* Don't descend into the ir_dereference_variable below. */ 148 return visit_continue_with_parent; 149} 150 151ir_visitor_status 152ir_structure_reference_visitor::visit_enter(ir_assignment *ir) 153{ 154 if (ir->lhs->as_dereference_variable() && 155 ir->rhs->as_dereference_variable() && 156 !ir->condition) { 157 /* We'll split copies of a structure to copies of components, so don't 158 * descend to the ir_dereference_variables. 159 */ 160 return visit_continue_with_parent; 161 } 162 return visit_continue; 163} 164 165ir_visitor_status 166ir_structure_reference_visitor::visit_enter(ir_function_signature *ir) 167{ 168 /* We don't want to descend into the function parameters and 169 * dead-code eliminate them, so just accept the body here. 170 */ 171 visit_list_elements(this, &ir->body); 172 return visit_continue_with_parent; 173} 174 175class ir_structure_splitting_visitor : public ir_rvalue_visitor { 176public: 177 ir_structure_splitting_visitor(exec_list *vars) 178 { 179 this->variable_list = vars; 180 } 181 182 virtual ~ir_structure_splitting_visitor() 183 { 184 } 185 186 virtual ir_visitor_status visit_leave(ir_assignment *); 187 188 void split_deref(ir_dereference **deref); 189 void handle_rvalue(ir_rvalue **rvalue); 190 variable_entry2 *get_splitting_entry(ir_variable *var); 191 192 exec_list *variable_list; 193 void *mem_ctx; 194}; 195 196variable_entry2 * 197ir_structure_splitting_visitor::get_splitting_entry(ir_variable *var) 198{ 199 assert(var); 200 201 if (!var->type->is_record()) 202 return NULL; 203 204 foreach_iter(exec_list_iterator, iter, *this->variable_list) { 205 variable_entry2 *entry = (variable_entry2 *)iter.get(); 206 if (entry->var == var) { 207 return entry; 208 } 209 } 210 211 return NULL; 212} 213 214void 215ir_structure_splitting_visitor::split_deref(ir_dereference **deref) 216{ 217 if ((*deref)->ir_type != ir_type_dereference_record) 218 return; 219 220 ir_dereference_record *deref_record = (ir_dereference_record *)*deref; 221 ir_dereference_variable *deref_var = deref_record->record->as_dereference_variable(); 222 if (!deref_var) 223 return; 224 225 variable_entry2 *entry = get_splitting_entry(deref_var->var); 226 if (!entry) 227 return; 228 229 unsigned int i; 230 for (i = 0; i < entry->var->type->length; i++) { 231 if (strcmp(deref_record->field, 232 entry->var->type->fields.structure[i].name) == 0) 233 break; 234 } 235 assert(i != entry->var->type->length); 236 237 *deref = new(entry->mem_ctx) ir_dereference_variable(entry->components[i]); 238} 239 240void 241ir_structure_splitting_visitor::handle_rvalue(ir_rvalue **rvalue) 242{ 243 if (!*rvalue) 244 return; 245 246 ir_dereference *deref = (*rvalue)->as_dereference(); 247 248 if (!deref) 249 return; 250 251 split_deref(&deref); 252 *rvalue = deref; 253} 254 255ir_visitor_status 256ir_structure_splitting_visitor::visit_leave(ir_assignment *ir) 257{ 258 ir_dereference_variable *lhs_deref = ir->lhs->as_dereference_variable(); 259 ir_dereference_variable *rhs_deref = ir->rhs->as_dereference_variable(); 260 variable_entry2 *lhs_entry = lhs_deref ? get_splitting_entry(lhs_deref->var) : NULL; 261 variable_entry2 *rhs_entry = rhs_deref ? get_splitting_entry(rhs_deref->var) : NULL; 262 const glsl_type *type = ir->rhs->type; 263 264 if ((lhs_entry || rhs_entry) && !ir->condition) { 265 for (unsigned int i = 0; i < type->length; i++) { 266 ir_dereference *new_lhs, *new_rhs; 267 void *mem_ctx = lhs_entry ? lhs_entry->mem_ctx : rhs_entry->mem_ctx; 268 269 if (lhs_entry) { 270 new_lhs = new(mem_ctx) ir_dereference_variable(lhs_entry->components[i]); 271 } else { 272 new_lhs = new(mem_ctx) 273 ir_dereference_record(ir->lhs->clone(mem_ctx, NULL), 274 type->fields.structure[i].name); 275 } 276 277 if (rhs_entry) { 278 new_rhs = new(mem_ctx) ir_dereference_variable(rhs_entry->components[i]); 279 } else { 280 new_rhs = new(mem_ctx) 281 ir_dereference_record(ir->rhs->clone(mem_ctx, NULL), 282 type->fields.structure[i].name); 283 } 284 285 ir->insert_before(new(mem_ctx) ir_assignment(new_lhs, 286 new_rhs, 287 NULL)); 288 } 289 ir->remove(); 290 } else { 291 handle_rvalue(&ir->rhs); 292 split_deref(&ir->lhs); 293 } 294 295 handle_rvalue(&ir->condition); 296 297 return visit_continue; 298} 299 300bool 301do_structure_splitting(exec_list *instructions) 302{ 303 ir_structure_reference_visitor refs; 304 305 visit_list_elements(&refs, instructions); 306 307 /* Trim out variables we can't split. */ 308 foreach_iter(exec_list_iterator, iter, refs.variable_list) { 309 variable_entry2 *entry = (variable_entry2 *)iter.get(); 310 311 if (debug) { 312 printf("structure %s@%p: decl %d, whole_access %d\n", 313 entry->var->name, (void *) entry->var, entry->declaration, 314 entry->whole_structure_access); 315 } 316 317 if (!entry->declaration || entry->whole_structure_access) { 318 entry->remove(); 319 } 320 } 321 322 if (refs.variable_list.is_empty()) 323 return false; 324 325 void *mem_ctx = talloc_new(NULL); 326 327 /* Replace the decls of the structures to be split with their split 328 * components. 329 */ 330 foreach_iter(exec_list_iterator, iter, refs.variable_list) { 331 variable_entry2 *entry = (variable_entry2 *)iter.get(); 332 const struct glsl_type *type = entry->var->type; 333 334 entry->mem_ctx = talloc_parent(entry->var); 335 336 entry->components = talloc_array(mem_ctx, 337 ir_variable *, 338 type->length); 339 340 for (unsigned int i = 0; i < entry->var->type->length; i++) { 341 const char *name = talloc_asprintf(mem_ctx, "%s_%s", 342 entry->var->name, 343 type->fields.structure[i].name); 344 345 entry->components[i] = 346 new(entry->mem_ctx) ir_variable(type->fields.structure[i].type, 347 name, 348 ir_var_temporary); 349 entry->var->insert_before(entry->components[i]); 350 } 351 352 entry->var->remove(); 353 } 354 355 ir_structure_splitting_visitor split(&refs.variable_list); 356 visit_list_elements(&split, instructions); 357 358 talloc_free(mem_ctx); 359 360 return true; 361} 362