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_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_rvalue_visitor.h" 38 #include "compiler/glsl_types.h" 39 40 namespace { 41 42 static bool debug = false; 43 44 class variable_entry : public exec_node 45 { 46 public: 47 variable_entry(ir_variable *var) 48 { 49 this->var = var; 50 this->whole_structure_access = 0; 51 this->declaration = false; 52 this->components = NULL; 53 this->mem_ctx = NULL; 54 } 55 56 ir_variable *var; /* The key: the variable's pointer. */ 57 58 /** Number of times the variable is referenced, including assignments. */ 59 unsigned whole_structure_access; 60 61 /* If the variable had a decl we can work with in the instruction 62 * stream. We can't do splitting on function arguments, which 63 * don't get this variable set. 64 */ 65 bool declaration; 66 67 ir_variable **components; 68 69 /** ralloc_parent(this->var) -- the shader's ralloc context. */ 70 void *mem_ctx; 71 }; 72 73 74 class ir_structure_reference_visitor : public ir_hierarchical_visitor { 75 public: 76 ir_structure_reference_visitor(void) 77 { 78 this->mem_ctx = ralloc_context(NULL); 79 this->variable_list.make_empty(); 80 } 81 82 ~ir_structure_reference_visitor(void) 83 { 84 ralloc_free(mem_ctx); 85 } 86 87 virtual ir_visitor_status visit(ir_variable *); 88 virtual ir_visitor_status visit(ir_dereference_variable *); 89 virtual ir_visitor_status visit_enter(ir_dereference_record *); 90 virtual ir_visitor_status visit_enter(ir_assignment *); 91 virtual ir_visitor_status visit_enter(ir_function_signature *); 92 93 variable_entry *get_variable_entry(ir_variable *var); 94 95 /* List of variable_entry */ 96 exec_list variable_list; 97 98 void *mem_ctx; 99 }; 100 101 variable_entry * 102 ir_structure_reference_visitor::get_variable_entry(ir_variable *var) 103 { 104 assert(var); 105 106 if (!var->type->is_record() || 107 var->data.mode == ir_var_uniform || var->data.mode == ir_var_shader_storage || 108 var->data.mode == ir_var_shader_in || var->data.mode == ir_var_shader_out) 109 return NULL; 110 111 foreach_in_list(variable_entry, entry, &this->variable_list) { 112 if (entry->var == var) 113 return entry; 114 } 115 116 variable_entry *entry = new(mem_ctx) variable_entry(var); 117 this->variable_list.push_tail(entry); 118 return entry; 119 } 120 121 122 ir_visitor_status 123 ir_structure_reference_visitor::visit(ir_variable *ir) 124 { 125 variable_entry *entry = this->get_variable_entry(ir); 126 127 if (entry) 128 entry->declaration = true; 129 130 return visit_continue; 131 } 132 133 ir_visitor_status 134 ir_structure_reference_visitor::visit(ir_dereference_variable *ir) 135 { 136 ir_variable *const var = ir->variable_referenced(); 137 variable_entry *entry = this->get_variable_entry(var); 138 139 if (entry) 140 entry->whole_structure_access++; 141 142 return visit_continue; 143 } 144 145 ir_visitor_status 146 ir_structure_reference_visitor::visit_enter(ir_dereference_record *ir) 147 { 148 (void) ir; 149 /* Don't descend into the ir_dereference_variable below. */ 150 return visit_continue_with_parent; 151 } 152 153 ir_visitor_status 154 ir_structure_reference_visitor::visit_enter(ir_assignment *ir) 155 { 156 /* If there are no structure references yet, no need to bother with 157 * processing the expression tree. 158 */ 159 if (this->variable_list.is_empty()) 160 return visit_continue_with_parent; 161 162 if (ir->lhs->as_dereference_variable() && 163 ir->rhs->as_dereference_variable() && 164 !ir->condition) { 165 /* We'll split copies of a structure to copies of components, so don't 166 * descend to the ir_dereference_variables. 167 */ 168 return visit_continue_with_parent; 169 } 170 return visit_continue; 171 } 172 173 ir_visitor_status 174 ir_structure_reference_visitor::visit_enter(ir_function_signature *ir) 175 { 176 /* We don't have logic for structure-splitting function arguments, 177 * so just look at the body instructions and not the parameter 178 * declarations. 179 */ 180 visit_list_elements(this, &ir->body); 181 return visit_continue_with_parent; 182 } 183 184 class ir_structure_splitting_visitor : public ir_rvalue_visitor { 185 public: 186 ir_structure_splitting_visitor(exec_list *vars) 187 { 188 this->variable_list = vars; 189 } 190 191 virtual ~ir_structure_splitting_visitor() 192 { 193 } 194 195 virtual ir_visitor_status visit_leave(ir_assignment *); 196 197 void split_deref(ir_dereference **deref); 198 void handle_rvalue(ir_rvalue **rvalue); 199 variable_entry *get_splitting_entry(ir_variable *var); 200 201 exec_list *variable_list; 202 }; 203 204 variable_entry * 205 ir_structure_splitting_visitor::get_splitting_entry(ir_variable *var) 206 { 207 assert(var); 208 209 if (!var->type->is_record()) 210 return NULL; 211 212 foreach_in_list(variable_entry, entry, this->variable_list) { 213 if (entry->var == var) { 214 return entry; 215 } 216 } 217 218 return NULL; 219 } 220 221 void 222 ir_structure_splitting_visitor::split_deref(ir_dereference **deref) 223 { 224 if ((*deref)->ir_type != ir_type_dereference_record) 225 return; 226 227 ir_dereference_record *deref_record = (ir_dereference_record *)*deref; 228 ir_dereference_variable *deref_var = deref_record->record->as_dereference_variable(); 229 if (!deref_var) 230 return; 231 232 variable_entry *entry = get_splitting_entry(deref_var->var); 233 if (!entry) 234 return; 235 236 int i = deref_record->field_idx; 237 assert(i >= 0); 238 assert((unsigned) i < entry->var->type->length); 239 240 *deref = new(entry->mem_ctx) ir_dereference_variable(entry->components[i]); 241 } 242 243 void 244 ir_structure_splitting_visitor::handle_rvalue(ir_rvalue **rvalue) 245 { 246 if (!*rvalue) 247 return; 248 249 ir_dereference *deref = (*rvalue)->as_dereference(); 250 251 if (!deref) 252 return; 253 254 split_deref(&deref); 255 *rvalue = deref; 256 } 257 258 ir_visitor_status 259 ir_structure_splitting_visitor::visit_leave(ir_assignment *ir) 260 { 261 ir_dereference_variable *lhs_deref = ir->lhs->as_dereference_variable(); 262 ir_dereference_variable *rhs_deref = ir->rhs->as_dereference_variable(); 263 variable_entry *lhs_entry = lhs_deref ? get_splitting_entry(lhs_deref->var) : NULL; 264 variable_entry *rhs_entry = rhs_deref ? get_splitting_entry(rhs_deref->var) : NULL; 265 const glsl_type *type = ir->rhs->type; 266 267 if ((lhs_entry || rhs_entry) && !ir->condition) { 268 for (unsigned int i = 0; i < type->length; i++) { 269 ir_dereference *new_lhs, *new_rhs; 270 void *mem_ctx = lhs_entry ? lhs_entry->mem_ctx : rhs_entry->mem_ctx; 271 272 if (lhs_entry) { 273 new_lhs = new(mem_ctx) ir_dereference_variable(lhs_entry->components[i]); 274 } else { 275 new_lhs = new(mem_ctx) 276 ir_dereference_record(ir->lhs->clone(mem_ctx, NULL), 277 type->fields.structure[i].name); 278 } 279 280 if (rhs_entry) { 281 new_rhs = new(mem_ctx) ir_dereference_variable(rhs_entry->components[i]); 282 } else { 283 new_rhs = new(mem_ctx) 284 ir_dereference_record(ir->rhs->clone(mem_ctx, NULL), 285 type->fields.structure[i].name); 286 } 287 288 ir->insert_before(new(mem_ctx) ir_assignment(new_lhs, new_rhs)); 289 } 290 ir->remove(); 291 } else { 292 handle_rvalue(&ir->rhs); 293 split_deref(&ir->lhs); 294 } 295 296 handle_rvalue(&ir->condition); 297 298 return visit_continue; 299 } 300 301 } /* unnamed namespace */ 302 303 bool 304 do_structure_splitting(exec_list *instructions) 305 { 306 ir_structure_reference_visitor refs; 307 308 visit_list_elements(&refs, instructions); 309 310 /* Trim out variables we can't split. */ 311 foreach_in_list_safe(variable_entry, entry, &refs.variable_list) { 312 if (debug) { 313 printf("structure %s@%p: decl %d, whole_access %d\n", 314 entry->var->name, (void *) entry->var, entry->declaration, 315 entry->whole_structure_access); 316 } 317 318 if (!entry->declaration || entry->whole_structure_access) { 319 entry->remove(); 320 } 321 } 322 323 if (refs.variable_list.is_empty()) 324 return false; 325 326 void *mem_ctx = ralloc_context(NULL); 327 328 /* Replace the decls of the structures to be split with their split 329 * components. 330 */ 331 foreach_in_list_safe(variable_entry, entry, &refs.variable_list) { 332 const struct glsl_type *type = entry->var->type; 333 334 entry->mem_ctx = ralloc_parent(entry->var); 335 336 entry->components = ralloc_array(mem_ctx, ir_variable *, type->length); 337 338 for (unsigned int i = 0; i < entry->var->type->length; i++) { 339 const char *name = ralloc_asprintf(mem_ctx, "%s_%s", entry->var->name, 340 type->fields.structure[i].name); 341 ir_variable *new_var = 342 new(entry->mem_ctx) ir_variable(type->fields.structure[i].type, 343 name, 344 (ir_variable_mode) entry->var->data.mode); 345 346 if (type->fields.structure[i].type->without_array()->is_image()) { 347 /* Do not lose memory/format qualifiers for images declared inside 348 * structures as allowed by ARB_bindless_texture. 349 */ 350 new_var->data.memory_read_only = 351 type->fields.structure[i].memory_read_only; 352 new_var->data.memory_write_only = 353 type->fields.structure[i].memory_write_only; 354 new_var->data.memory_coherent = 355 type->fields.structure[i].memory_coherent; 356 new_var->data.memory_volatile = 357 type->fields.structure[i].memory_volatile; 358 new_var->data.memory_restrict = 359 type->fields.structure[i].memory_restrict; 360 new_var->data.image_format = 361 type->fields.structure[i].image_format; 362 } 363 364 entry->components[i] = new_var; 365 entry->var->insert_before(entry->components[i]); 366 } 367 368 entry->var->remove(); 369 } 370 371 ir_structure_splitting_visitor split(&refs.variable_list); 372 visit_list_elements(&split, instructions); 373 374 ralloc_free(mem_ctx); 375 376 return true; 377 } 378