1bf215546Sopenharmony_ci/* 2bf215546Sopenharmony_ci * Copyright © 2010 Intel Corporation 3bf215546Sopenharmony_ci * 4bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 5bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"), 6bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation 7bf215546Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8bf215546Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the 9bf215546Sopenharmony_ci * Software is furnished to do so, subject to the following conditions: 10bf215546Sopenharmony_ci * 11bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the next 12bf215546Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the 13bf215546Sopenharmony_ci * Software. 14bf215546Sopenharmony_ci * 15bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18bf215546Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19bf215546Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20bf215546Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21bf215546Sopenharmony_ci * DEALINGS IN THE SOFTWARE. 22bf215546Sopenharmony_ci */ 23bf215546Sopenharmony_ci 24bf215546Sopenharmony_ci/** 25bf215546Sopenharmony_ci * \file opt_array_splitting.cpp 26bf215546Sopenharmony_ci * 27bf215546Sopenharmony_ci * If an array is always dereferenced with a constant index, then 28bf215546Sopenharmony_ci * split it apart into its elements, making it more amenable to other 29bf215546Sopenharmony_ci * optimization passes. 30bf215546Sopenharmony_ci * 31bf215546Sopenharmony_ci * This skips uniform/varying arrays, which would need careful 32bf215546Sopenharmony_ci * handling due to their ir->location fields tying them to the GL API 33bf215546Sopenharmony_ci * and other shader stages. 34bf215546Sopenharmony_ci */ 35bf215546Sopenharmony_ci 36bf215546Sopenharmony_ci#include "ir.h" 37bf215546Sopenharmony_ci#include "ir_visitor.h" 38bf215546Sopenharmony_ci#include "ir_rvalue_visitor.h" 39bf215546Sopenharmony_ci#include "compiler/glsl_types.h" 40bf215546Sopenharmony_ci 41bf215546Sopenharmony_cistatic bool debug = false; 42bf215546Sopenharmony_ci 43bf215546Sopenharmony_cinamespace { 44bf215546Sopenharmony_ci 45bf215546Sopenharmony_cinamespace opt_array_splitting { 46bf215546Sopenharmony_ci 47bf215546Sopenharmony_ciclass variable_entry : public exec_node 48bf215546Sopenharmony_ci{ 49bf215546Sopenharmony_cipublic: 50bf215546Sopenharmony_ci variable_entry(ir_variable *var) 51bf215546Sopenharmony_ci { 52bf215546Sopenharmony_ci this->var = var; 53bf215546Sopenharmony_ci this->split = true; 54bf215546Sopenharmony_ci this->declaration = false; 55bf215546Sopenharmony_ci this->components = NULL; 56bf215546Sopenharmony_ci this->mem_ctx = NULL; 57bf215546Sopenharmony_ci if (var->type->is_array()) 58bf215546Sopenharmony_ci this->size = var->type->length; 59bf215546Sopenharmony_ci else 60bf215546Sopenharmony_ci this->size = var->type->matrix_columns; 61bf215546Sopenharmony_ci } 62bf215546Sopenharmony_ci 63bf215546Sopenharmony_ci ir_variable *var; /* The key: the variable's pointer. */ 64bf215546Sopenharmony_ci unsigned size; /* array length or matrix columns */ 65bf215546Sopenharmony_ci 66bf215546Sopenharmony_ci /** Whether this array should be split or not. */ 67bf215546Sopenharmony_ci bool split; 68bf215546Sopenharmony_ci 69bf215546Sopenharmony_ci /* If the variable had a decl we can work with in the instruction 70bf215546Sopenharmony_ci * stream. We can't do splitting on function arguments, which 71bf215546Sopenharmony_ci * don't get this variable set. 72bf215546Sopenharmony_ci */ 73bf215546Sopenharmony_ci bool declaration; 74bf215546Sopenharmony_ci 75bf215546Sopenharmony_ci ir_variable **components; 76bf215546Sopenharmony_ci 77bf215546Sopenharmony_ci /** ralloc_parent(this->var) -- the shader's talloc context. */ 78bf215546Sopenharmony_ci void *mem_ctx; 79bf215546Sopenharmony_ci}; 80bf215546Sopenharmony_ci 81bf215546Sopenharmony_ci} /* namespace */ 82bf215546Sopenharmony_ci 83bf215546Sopenharmony_ciusing namespace opt_array_splitting; 84bf215546Sopenharmony_ci 85bf215546Sopenharmony_ci/** 86bf215546Sopenharmony_ci * This class does a walk over the tree, coming up with the set of 87bf215546Sopenharmony_ci * variables that could be split by looking to see if they are arrays 88bf215546Sopenharmony_ci * that are only ever constant-index dereferenced. 89bf215546Sopenharmony_ci */ 90bf215546Sopenharmony_ciclass ir_array_reference_visitor : public ir_hierarchical_visitor { 91bf215546Sopenharmony_cipublic: 92bf215546Sopenharmony_ci ir_array_reference_visitor(void) 93bf215546Sopenharmony_ci { 94bf215546Sopenharmony_ci this->mem_ctx = ralloc_context(NULL); 95bf215546Sopenharmony_ci this->variable_list.make_empty(); 96bf215546Sopenharmony_ci this->in_whole_array_copy = false; 97bf215546Sopenharmony_ci } 98bf215546Sopenharmony_ci 99bf215546Sopenharmony_ci ~ir_array_reference_visitor(void) 100bf215546Sopenharmony_ci { 101bf215546Sopenharmony_ci ralloc_free(mem_ctx); 102bf215546Sopenharmony_ci } 103bf215546Sopenharmony_ci 104bf215546Sopenharmony_ci bool get_split_list(exec_list *instructions, bool linked); 105bf215546Sopenharmony_ci 106bf215546Sopenharmony_ci virtual ir_visitor_status visit(ir_variable *); 107bf215546Sopenharmony_ci virtual ir_visitor_status visit(ir_dereference_variable *); 108bf215546Sopenharmony_ci virtual ir_visitor_status visit_enter(ir_assignment *); 109bf215546Sopenharmony_ci virtual ir_visitor_status visit_leave(ir_assignment *); 110bf215546Sopenharmony_ci virtual ir_visitor_status visit_enter(ir_dereference_array *); 111bf215546Sopenharmony_ci virtual ir_visitor_status visit_enter(ir_function_signature *); 112bf215546Sopenharmony_ci 113bf215546Sopenharmony_ci variable_entry *get_variable_entry(ir_variable *var); 114bf215546Sopenharmony_ci 115bf215546Sopenharmony_ci /* List of variable_entry */ 116bf215546Sopenharmony_ci exec_list variable_list; 117bf215546Sopenharmony_ci 118bf215546Sopenharmony_ci void *mem_ctx; 119bf215546Sopenharmony_ci 120bf215546Sopenharmony_ci bool in_whole_array_copy; 121bf215546Sopenharmony_ci}; 122bf215546Sopenharmony_ci 123bf215546Sopenharmony_ci} /* namespace */ 124bf215546Sopenharmony_ci 125bf215546Sopenharmony_civariable_entry * 126bf215546Sopenharmony_ciir_array_reference_visitor::get_variable_entry(ir_variable *var) 127bf215546Sopenharmony_ci{ 128bf215546Sopenharmony_ci assert(var); 129bf215546Sopenharmony_ci 130bf215546Sopenharmony_ci if (var->data.mode != ir_var_auto && 131bf215546Sopenharmony_ci var->data.mode != ir_var_temporary) 132bf215546Sopenharmony_ci return NULL; 133bf215546Sopenharmony_ci 134bf215546Sopenharmony_ci if (!(var->type->is_array() || var->type->is_matrix())) 135bf215546Sopenharmony_ci return NULL; 136bf215546Sopenharmony_ci 137bf215546Sopenharmony_ci /* If the array hasn't been sized yet, we can't split it. After 138bf215546Sopenharmony_ci * linking, this should be resolved. 139bf215546Sopenharmony_ci */ 140bf215546Sopenharmony_ci if (var->type->is_unsized_array()) 141bf215546Sopenharmony_ci return NULL; 142bf215546Sopenharmony_ci 143bf215546Sopenharmony_ci /* FIXME: arrays of arrays are not handled correctly by this pass so we 144bf215546Sopenharmony_ci * skip it for now. While the pass will create functioning code it actually 145bf215546Sopenharmony_ci * produces worse code. 146bf215546Sopenharmony_ci * 147bf215546Sopenharmony_ci * For example the array: 148bf215546Sopenharmony_ci * 149bf215546Sopenharmony_ci * int[3][2] a; 150bf215546Sopenharmony_ci * 151bf215546Sopenharmony_ci * ends up being split up into: 152bf215546Sopenharmony_ci * 153bf215546Sopenharmony_ci * int[3][2] a_0; 154bf215546Sopenharmony_ci * int[3][2] a_1; 155bf215546Sopenharmony_ci * int[3][2] a_2; 156bf215546Sopenharmony_ci * 157bf215546Sopenharmony_ci * And we end up referencing each of these new arrays for example: 158bf215546Sopenharmony_ci * 159bf215546Sopenharmony_ci * a[0][1] will be turned into a_0[0][1] 160bf215546Sopenharmony_ci * a[1][0] will be turned into a_1[1][0] 161bf215546Sopenharmony_ci * a[2][0] will be turned into a_2[2][0] 162bf215546Sopenharmony_ci */ 163bf215546Sopenharmony_ci if (var->type->is_array() && var->type->fields.array->is_array()) 164bf215546Sopenharmony_ci return NULL; 165bf215546Sopenharmony_ci 166bf215546Sopenharmony_ci foreach_in_list(variable_entry, entry, &this->variable_list) { 167bf215546Sopenharmony_ci if (entry->var == var) 168bf215546Sopenharmony_ci return entry; 169bf215546Sopenharmony_ci } 170bf215546Sopenharmony_ci 171bf215546Sopenharmony_ci variable_entry *entry = new(mem_ctx) variable_entry(var); 172bf215546Sopenharmony_ci this->variable_list.push_tail(entry); 173bf215546Sopenharmony_ci return entry; 174bf215546Sopenharmony_ci} 175bf215546Sopenharmony_ci 176bf215546Sopenharmony_ci 177bf215546Sopenharmony_ciir_visitor_status 178bf215546Sopenharmony_ciir_array_reference_visitor::visit(ir_variable *ir) 179bf215546Sopenharmony_ci{ 180bf215546Sopenharmony_ci variable_entry *entry = this->get_variable_entry(ir); 181bf215546Sopenharmony_ci 182bf215546Sopenharmony_ci if (entry) 183bf215546Sopenharmony_ci entry->declaration = true; 184bf215546Sopenharmony_ci 185bf215546Sopenharmony_ci return visit_continue; 186bf215546Sopenharmony_ci} 187bf215546Sopenharmony_ci 188bf215546Sopenharmony_ciir_visitor_status 189bf215546Sopenharmony_ciir_array_reference_visitor::visit_enter(ir_assignment *ir) 190bf215546Sopenharmony_ci{ 191bf215546Sopenharmony_ci in_whole_array_copy = 192bf215546Sopenharmony_ci ir->lhs->type->is_array() && ir->whole_variable_written(); 193bf215546Sopenharmony_ci 194bf215546Sopenharmony_ci return visit_continue; 195bf215546Sopenharmony_ci} 196bf215546Sopenharmony_ci 197bf215546Sopenharmony_ciir_visitor_status 198bf215546Sopenharmony_ciir_array_reference_visitor::visit_leave(ir_assignment *) 199bf215546Sopenharmony_ci{ 200bf215546Sopenharmony_ci in_whole_array_copy = false; 201bf215546Sopenharmony_ci 202bf215546Sopenharmony_ci return visit_continue; 203bf215546Sopenharmony_ci} 204bf215546Sopenharmony_ci 205bf215546Sopenharmony_ciir_visitor_status 206bf215546Sopenharmony_ciir_array_reference_visitor::visit(ir_dereference_variable *ir) 207bf215546Sopenharmony_ci{ 208bf215546Sopenharmony_ci variable_entry *entry = this->get_variable_entry(ir->var); 209bf215546Sopenharmony_ci 210bf215546Sopenharmony_ci /* Allow whole-array assignments on the LHS. We can split those 211bf215546Sopenharmony_ci * by "unrolling" the assignment into component-wise assignments. 212bf215546Sopenharmony_ci */ 213bf215546Sopenharmony_ci if (in_assignee && in_whole_array_copy) 214bf215546Sopenharmony_ci return visit_continue; 215bf215546Sopenharmony_ci 216bf215546Sopenharmony_ci /* If we made it to here without seeing an ir_dereference_array, 217bf215546Sopenharmony_ci * then the dereference of this array didn't have a constant index 218bf215546Sopenharmony_ci * (see the visit_continue_with_parent below), so we can't split 219bf215546Sopenharmony_ci * the variable. 220bf215546Sopenharmony_ci */ 221bf215546Sopenharmony_ci if (entry) 222bf215546Sopenharmony_ci entry->split = false; 223bf215546Sopenharmony_ci 224bf215546Sopenharmony_ci return visit_continue; 225bf215546Sopenharmony_ci} 226bf215546Sopenharmony_ci 227bf215546Sopenharmony_ciir_visitor_status 228bf215546Sopenharmony_ciir_array_reference_visitor::visit_enter(ir_dereference_array *ir) 229bf215546Sopenharmony_ci{ 230bf215546Sopenharmony_ci ir_dereference_variable *deref = ir->array->as_dereference_variable(); 231bf215546Sopenharmony_ci if (!deref) 232bf215546Sopenharmony_ci return visit_continue; 233bf215546Sopenharmony_ci 234bf215546Sopenharmony_ci variable_entry *entry = this->get_variable_entry(deref->var); 235bf215546Sopenharmony_ci 236bf215546Sopenharmony_ci /* If the access to the array has a variable index, we wouldn't 237bf215546Sopenharmony_ci * know which split variable this dereference should go to. 238bf215546Sopenharmony_ci */ 239bf215546Sopenharmony_ci if (!ir->array_index->as_constant()) { 240bf215546Sopenharmony_ci if (entry) 241bf215546Sopenharmony_ci entry->split = false; 242bf215546Sopenharmony_ci /* This variable indexing could come from a different array dereference 243bf215546Sopenharmony_ci * that also has variable indexing, that is, something like a[b[a[b[0]]]]. 244bf215546Sopenharmony_ci * If we return visit_continue_with_parent here for the first appearence 245bf215546Sopenharmony_ci * of a, then we can miss that b also has indirect indexing (if this is 246bf215546Sopenharmony_ci * the only place in the program where such indirect indexing into b 247bf215546Sopenharmony_ci * happens), so keep going. 248bf215546Sopenharmony_ci */ 249bf215546Sopenharmony_ci return visit_continue; 250bf215546Sopenharmony_ci } 251bf215546Sopenharmony_ci 252bf215546Sopenharmony_ci /* If the index is also array dereference, visit index. */ 253bf215546Sopenharmony_ci if (ir->array_index->as_dereference_array()) 254bf215546Sopenharmony_ci visit_enter(ir->array_index->as_dereference_array()); 255bf215546Sopenharmony_ci 256bf215546Sopenharmony_ci return visit_continue_with_parent; 257bf215546Sopenharmony_ci} 258bf215546Sopenharmony_ci 259bf215546Sopenharmony_ciir_visitor_status 260bf215546Sopenharmony_ciir_array_reference_visitor::visit_enter(ir_function_signature *ir) 261bf215546Sopenharmony_ci{ 262bf215546Sopenharmony_ci /* We don't have logic for array-splitting function arguments, 263bf215546Sopenharmony_ci * so just look at the body instructions and not the parameter 264bf215546Sopenharmony_ci * declarations. 265bf215546Sopenharmony_ci */ 266bf215546Sopenharmony_ci visit_list_elements(this, &ir->body); 267bf215546Sopenharmony_ci return visit_continue_with_parent; 268bf215546Sopenharmony_ci} 269bf215546Sopenharmony_ci 270bf215546Sopenharmony_cibool 271bf215546Sopenharmony_ciir_array_reference_visitor::get_split_list(exec_list *instructions, 272bf215546Sopenharmony_ci bool linked) 273bf215546Sopenharmony_ci{ 274bf215546Sopenharmony_ci visit_list_elements(this, instructions); 275bf215546Sopenharmony_ci 276bf215546Sopenharmony_ci /* If the shaders aren't linked yet, we can't mess with global 277bf215546Sopenharmony_ci * declarations, which need to be matched by name across shaders. 278bf215546Sopenharmony_ci */ 279bf215546Sopenharmony_ci if (!linked) { 280bf215546Sopenharmony_ci foreach_in_list(ir_instruction, node, instructions) { 281bf215546Sopenharmony_ci ir_variable *var = node->as_variable(); 282bf215546Sopenharmony_ci if (var) { 283bf215546Sopenharmony_ci variable_entry *entry = get_variable_entry(var); 284bf215546Sopenharmony_ci if (entry) 285bf215546Sopenharmony_ci entry->remove(); 286bf215546Sopenharmony_ci } 287bf215546Sopenharmony_ci } 288bf215546Sopenharmony_ci } 289bf215546Sopenharmony_ci 290bf215546Sopenharmony_ci /* Trim out variables we found that we can't split. */ 291bf215546Sopenharmony_ci foreach_in_list_safe(variable_entry, entry, &variable_list) { 292bf215546Sopenharmony_ci if (debug) { 293bf215546Sopenharmony_ci printf("array %s@%p: decl %d, split %d\n", 294bf215546Sopenharmony_ci entry->var->name, (void *) entry->var, entry->declaration, 295bf215546Sopenharmony_ci entry->split); 296bf215546Sopenharmony_ci } 297bf215546Sopenharmony_ci 298bf215546Sopenharmony_ci if (!(entry->declaration && entry->split)) { 299bf215546Sopenharmony_ci entry->remove(); 300bf215546Sopenharmony_ci } 301bf215546Sopenharmony_ci } 302bf215546Sopenharmony_ci 303bf215546Sopenharmony_ci return !variable_list.is_empty(); 304bf215546Sopenharmony_ci} 305bf215546Sopenharmony_ci 306bf215546Sopenharmony_ci/** 307bf215546Sopenharmony_ci * This class rewrites the dereferences of arrays that have been split 308bf215546Sopenharmony_ci * to use the newly created ir_variables for each component. 309bf215546Sopenharmony_ci */ 310bf215546Sopenharmony_ciclass ir_array_splitting_visitor : public ir_rvalue_visitor { 311bf215546Sopenharmony_cipublic: 312bf215546Sopenharmony_ci ir_array_splitting_visitor(exec_list *vars) 313bf215546Sopenharmony_ci { 314bf215546Sopenharmony_ci this->variable_list = vars; 315bf215546Sopenharmony_ci } 316bf215546Sopenharmony_ci 317bf215546Sopenharmony_ci virtual ~ir_array_splitting_visitor() 318bf215546Sopenharmony_ci { 319bf215546Sopenharmony_ci } 320bf215546Sopenharmony_ci 321bf215546Sopenharmony_ci virtual ir_visitor_status visit_leave(ir_assignment *); 322bf215546Sopenharmony_ci 323bf215546Sopenharmony_ci void split_deref(ir_dereference **deref); 324bf215546Sopenharmony_ci void handle_rvalue(ir_rvalue **rvalue); 325bf215546Sopenharmony_ci variable_entry *get_splitting_entry(ir_variable *var); 326bf215546Sopenharmony_ci 327bf215546Sopenharmony_ci exec_list *variable_list; 328bf215546Sopenharmony_ci}; 329bf215546Sopenharmony_ci 330bf215546Sopenharmony_civariable_entry * 331bf215546Sopenharmony_ciir_array_splitting_visitor::get_splitting_entry(ir_variable *var) 332bf215546Sopenharmony_ci{ 333bf215546Sopenharmony_ci assert(var); 334bf215546Sopenharmony_ci 335bf215546Sopenharmony_ci foreach_in_list(variable_entry, entry, this->variable_list) { 336bf215546Sopenharmony_ci if (entry->var == var) { 337bf215546Sopenharmony_ci return entry; 338bf215546Sopenharmony_ci } 339bf215546Sopenharmony_ci } 340bf215546Sopenharmony_ci 341bf215546Sopenharmony_ci return NULL; 342bf215546Sopenharmony_ci} 343bf215546Sopenharmony_ci 344bf215546Sopenharmony_civoid 345bf215546Sopenharmony_ciir_array_splitting_visitor::split_deref(ir_dereference **deref) 346bf215546Sopenharmony_ci{ 347bf215546Sopenharmony_ci ir_dereference_array *deref_array = (*deref)->as_dereference_array(); 348bf215546Sopenharmony_ci if (!deref_array) 349bf215546Sopenharmony_ci return; 350bf215546Sopenharmony_ci 351bf215546Sopenharmony_ci ir_dereference_variable *deref_var = deref_array->array->as_dereference_variable(); 352bf215546Sopenharmony_ci if (!deref_var) 353bf215546Sopenharmony_ci return; 354bf215546Sopenharmony_ci ir_variable *var = deref_var->var; 355bf215546Sopenharmony_ci 356bf215546Sopenharmony_ci variable_entry *entry = get_splitting_entry(var); 357bf215546Sopenharmony_ci if (!entry) 358bf215546Sopenharmony_ci return; 359bf215546Sopenharmony_ci 360bf215546Sopenharmony_ci ir_constant *constant = deref_array->array_index->as_constant(); 361bf215546Sopenharmony_ci assert(constant); 362bf215546Sopenharmony_ci 363bf215546Sopenharmony_ci if (constant->value.i[0] >= 0 && constant->value.i[0] < (int)entry->size) { 364bf215546Sopenharmony_ci *deref = new(entry->mem_ctx) 365bf215546Sopenharmony_ci ir_dereference_variable(entry->components[constant->value.i[0]]); 366bf215546Sopenharmony_ci } else { 367bf215546Sopenharmony_ci /* There was a constant array access beyond the end of the 368bf215546Sopenharmony_ci * array. This might have happened due to constant folding 369bf215546Sopenharmony_ci * after the initial parse. This produces an undefined value, 370bf215546Sopenharmony_ci * but shouldn't crash. Just give them an uninitialized 371bf215546Sopenharmony_ci * variable. 372bf215546Sopenharmony_ci */ 373bf215546Sopenharmony_ci ir_variable *temp = new(entry->mem_ctx) ir_variable(deref_array->type, 374bf215546Sopenharmony_ci "undef", 375bf215546Sopenharmony_ci ir_var_temporary); 376bf215546Sopenharmony_ci entry->components[0]->insert_before(temp); 377bf215546Sopenharmony_ci *deref = new(entry->mem_ctx) ir_dereference_variable(temp); 378bf215546Sopenharmony_ci } 379bf215546Sopenharmony_ci} 380bf215546Sopenharmony_ci 381bf215546Sopenharmony_civoid 382bf215546Sopenharmony_ciir_array_splitting_visitor::handle_rvalue(ir_rvalue **rvalue) 383bf215546Sopenharmony_ci{ 384bf215546Sopenharmony_ci if (!*rvalue) 385bf215546Sopenharmony_ci return; 386bf215546Sopenharmony_ci 387bf215546Sopenharmony_ci ir_dereference *deref = (*rvalue)->as_dereference(); 388bf215546Sopenharmony_ci 389bf215546Sopenharmony_ci if (!deref) 390bf215546Sopenharmony_ci return; 391bf215546Sopenharmony_ci 392bf215546Sopenharmony_ci split_deref(&deref); 393bf215546Sopenharmony_ci *rvalue = deref; 394bf215546Sopenharmony_ci} 395bf215546Sopenharmony_ci 396bf215546Sopenharmony_ciir_visitor_status 397bf215546Sopenharmony_ciir_array_splitting_visitor::visit_leave(ir_assignment *ir) 398bf215546Sopenharmony_ci{ 399bf215546Sopenharmony_ci /* The normal rvalue visitor skips the LHS of assignments, but we 400bf215546Sopenharmony_ci * need to process those just the same. 401bf215546Sopenharmony_ci */ 402bf215546Sopenharmony_ci ir_rvalue *lhs = ir->lhs; 403bf215546Sopenharmony_ci 404bf215546Sopenharmony_ci /* "Unroll" any whole array assignments, creating assignments for 405bf215546Sopenharmony_ci * each array element. Then, do splitting on each new assignment. 406bf215546Sopenharmony_ci */ 407bf215546Sopenharmony_ci if (lhs->type->is_array() && ir->whole_variable_written() && 408bf215546Sopenharmony_ci get_splitting_entry(ir->whole_variable_written())) { 409bf215546Sopenharmony_ci void *mem_ctx = ralloc_parent(ir); 410bf215546Sopenharmony_ci 411bf215546Sopenharmony_ci for (unsigned i = 0; i < lhs->type->length; i++) { 412bf215546Sopenharmony_ci ir_rvalue *lhs_i = 413bf215546Sopenharmony_ci new(mem_ctx) ir_dereference_array(ir->lhs->clone(mem_ctx, NULL), 414bf215546Sopenharmony_ci new(mem_ctx) ir_constant(i)); 415bf215546Sopenharmony_ci ir_rvalue *rhs_i = 416bf215546Sopenharmony_ci new(mem_ctx) ir_dereference_array(ir->rhs->clone(mem_ctx, NULL), 417bf215546Sopenharmony_ci new(mem_ctx) ir_constant(i)); 418bf215546Sopenharmony_ci 419bf215546Sopenharmony_ci ir_assignment *assign_i = new(mem_ctx) ir_assignment(lhs_i, rhs_i); 420bf215546Sopenharmony_ci 421bf215546Sopenharmony_ci ir->insert_before(assign_i); 422bf215546Sopenharmony_ci assign_i->accept(this); 423bf215546Sopenharmony_ci } 424bf215546Sopenharmony_ci ir->remove(); 425bf215546Sopenharmony_ci return visit_continue; 426bf215546Sopenharmony_ci } 427bf215546Sopenharmony_ci 428bf215546Sopenharmony_ci handle_rvalue(&lhs); 429bf215546Sopenharmony_ci ir->lhs = lhs->as_dereference(); 430bf215546Sopenharmony_ci 431bf215546Sopenharmony_ci ir->lhs->accept(this); 432bf215546Sopenharmony_ci 433bf215546Sopenharmony_ci handle_rvalue(&ir->rhs); 434bf215546Sopenharmony_ci ir->rhs->accept(this); 435bf215546Sopenharmony_ci 436bf215546Sopenharmony_ci return visit_continue; 437bf215546Sopenharmony_ci} 438bf215546Sopenharmony_ci 439bf215546Sopenharmony_cibool 440bf215546Sopenharmony_cioptimize_split_arrays(exec_list *instructions, bool linked) 441bf215546Sopenharmony_ci{ 442bf215546Sopenharmony_ci ir_array_reference_visitor refs; 443bf215546Sopenharmony_ci if (!refs.get_split_list(instructions, linked)) 444bf215546Sopenharmony_ci return false; 445bf215546Sopenharmony_ci 446bf215546Sopenharmony_ci void *mem_ctx = ralloc_context(NULL); 447bf215546Sopenharmony_ci 448bf215546Sopenharmony_ci /* Replace the decls of the arrays to be split with their split 449bf215546Sopenharmony_ci * components. 450bf215546Sopenharmony_ci */ 451bf215546Sopenharmony_ci foreach_in_list(variable_entry, entry, &refs.variable_list) { 452bf215546Sopenharmony_ci const struct glsl_type *type = entry->var->type; 453bf215546Sopenharmony_ci const struct glsl_type *subtype; 454bf215546Sopenharmony_ci 455bf215546Sopenharmony_ci if (type->is_matrix()) 456bf215546Sopenharmony_ci subtype = type->column_type(); 457bf215546Sopenharmony_ci else 458bf215546Sopenharmony_ci subtype = type->fields.array; 459bf215546Sopenharmony_ci 460bf215546Sopenharmony_ci entry->mem_ctx = ralloc_parent(entry->var); 461bf215546Sopenharmony_ci 462bf215546Sopenharmony_ci entry->components = ralloc_array(mem_ctx, ir_variable *, entry->size); 463bf215546Sopenharmony_ci 464bf215546Sopenharmony_ci for (unsigned int i = 0; i < entry->size; i++) { 465bf215546Sopenharmony_ci const char *name = ralloc_asprintf(mem_ctx, "%s_%d", 466bf215546Sopenharmony_ci entry->var->name, i); 467bf215546Sopenharmony_ci ir_variable *new_var = 468bf215546Sopenharmony_ci new(entry->mem_ctx) ir_variable(subtype, name, ir_var_temporary); 469bf215546Sopenharmony_ci new_var->data.invariant = entry->var->data.invariant; 470bf215546Sopenharmony_ci new_var->data.precise = entry->var->data.precise; 471bf215546Sopenharmony_ci 472bf215546Sopenharmony_ci /* Do not lose memory/format qualifiers when arrays of images are 473bf215546Sopenharmony_ci * split. 474bf215546Sopenharmony_ci */ 475bf215546Sopenharmony_ci new_var->data.memory_read_only = entry->var->data.memory_read_only; 476bf215546Sopenharmony_ci new_var->data.memory_write_only = entry->var->data.memory_write_only; 477bf215546Sopenharmony_ci new_var->data.memory_coherent = entry->var->data.memory_coherent; 478bf215546Sopenharmony_ci new_var->data.memory_volatile = entry->var->data.memory_volatile; 479bf215546Sopenharmony_ci new_var->data.memory_restrict = entry->var->data.memory_restrict; 480bf215546Sopenharmony_ci new_var->data.image_format = entry->var->data.image_format; 481bf215546Sopenharmony_ci 482bf215546Sopenharmony_ci entry->components[i] = new_var; 483bf215546Sopenharmony_ci entry->var->insert_before(entry->components[i]); 484bf215546Sopenharmony_ci } 485bf215546Sopenharmony_ci 486bf215546Sopenharmony_ci entry->var->remove(); 487bf215546Sopenharmony_ci } 488bf215546Sopenharmony_ci 489bf215546Sopenharmony_ci ir_array_splitting_visitor split(&refs.variable_list); 490bf215546Sopenharmony_ci visit_list_elements(&split, instructions); 491bf215546Sopenharmony_ci 492bf215546Sopenharmony_ci if (debug) 493bf215546Sopenharmony_ci _mesa_print_ir(stdout, instructions, NULL); 494bf215546Sopenharmony_ci 495bf215546Sopenharmony_ci ralloc_free(mem_ctx); 496bf215546Sopenharmony_ci 497bf215546Sopenharmony_ci return true; 498bf215546Sopenharmony_ci 499bf215546Sopenharmony_ci} 500