101e04c3fSmrg/* 201e04c3fSmrg * Copyright © 2010 Intel Corporation 301e04c3fSmrg * 401e04c3fSmrg * Permission is hereby granted, free of charge, to any person obtaining a 501e04c3fSmrg * copy of this software and associated documentation files (the "Software"), 601e04c3fSmrg * to deal in the Software without restriction, including without limitation 701e04c3fSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 801e04c3fSmrg * and/or sell copies of the Software, and to permit persons to whom the 901e04c3fSmrg * Software is furnished to do so, subject to the following conditions: 1001e04c3fSmrg * 1101e04c3fSmrg * The above copyright notice and this permission notice (including the next 1201e04c3fSmrg * paragraph) shall be included in all copies or substantial portions of the 1301e04c3fSmrg * Software. 1401e04c3fSmrg * 1501e04c3fSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1601e04c3fSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1701e04c3fSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 1801e04c3fSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 1901e04c3fSmrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 2001e04c3fSmrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 2101e04c3fSmrg * DEALINGS IN THE SOFTWARE. 2201e04c3fSmrg */ 2301e04c3fSmrg 2401e04c3fSmrg/** 2501e04c3fSmrg * \file opt_array_splitting.cpp 2601e04c3fSmrg * 2701e04c3fSmrg * If an array is always dereferenced with a constant index, then 2801e04c3fSmrg * split it apart into its elements, making it more amenable to other 2901e04c3fSmrg * optimization passes. 3001e04c3fSmrg * 3101e04c3fSmrg * This skips uniform/varying arrays, which would need careful 3201e04c3fSmrg * handling due to their ir->location fields tying them to the GL API 3301e04c3fSmrg * and other shader stages. 3401e04c3fSmrg */ 3501e04c3fSmrg 3601e04c3fSmrg#include "ir.h" 3701e04c3fSmrg#include "ir_visitor.h" 3801e04c3fSmrg#include "ir_rvalue_visitor.h" 3901e04c3fSmrg#include "compiler/glsl_types.h" 4001e04c3fSmrg 4101e04c3fSmrgstatic bool debug = false; 4201e04c3fSmrg 4301e04c3fSmrgnamespace { 4401e04c3fSmrg 4501e04c3fSmrgnamespace opt_array_splitting { 4601e04c3fSmrg 4701e04c3fSmrgclass variable_entry : public exec_node 4801e04c3fSmrg{ 4901e04c3fSmrgpublic: 5001e04c3fSmrg variable_entry(ir_variable *var) 5101e04c3fSmrg { 5201e04c3fSmrg this->var = var; 5301e04c3fSmrg this->split = true; 5401e04c3fSmrg this->declaration = false; 5501e04c3fSmrg this->components = NULL; 5601e04c3fSmrg this->mem_ctx = NULL; 5701e04c3fSmrg if (var->type->is_array()) 5801e04c3fSmrg this->size = var->type->length; 5901e04c3fSmrg else 6001e04c3fSmrg this->size = var->type->matrix_columns; 6101e04c3fSmrg } 6201e04c3fSmrg 6301e04c3fSmrg ir_variable *var; /* The key: the variable's pointer. */ 6401e04c3fSmrg unsigned size; /* array length or matrix columns */ 6501e04c3fSmrg 6601e04c3fSmrg /** Whether this array should be split or not. */ 6701e04c3fSmrg bool split; 6801e04c3fSmrg 6901e04c3fSmrg /* If the variable had a decl we can work with in the instruction 7001e04c3fSmrg * stream. We can't do splitting on function arguments, which 7101e04c3fSmrg * don't get this variable set. 7201e04c3fSmrg */ 7301e04c3fSmrg bool declaration; 7401e04c3fSmrg 7501e04c3fSmrg ir_variable **components; 7601e04c3fSmrg 7701e04c3fSmrg /** ralloc_parent(this->var) -- the shader's talloc context. */ 7801e04c3fSmrg void *mem_ctx; 7901e04c3fSmrg}; 8001e04c3fSmrg 8101e04c3fSmrg} /* namespace */ 8201e04c3fSmrg 8301e04c3fSmrgusing namespace opt_array_splitting; 8401e04c3fSmrg 8501e04c3fSmrg/** 8601e04c3fSmrg * This class does a walk over the tree, coming up with the set of 8701e04c3fSmrg * variables that could be split by looking to see if they are arrays 8801e04c3fSmrg * that are only ever constant-index dereferenced. 8901e04c3fSmrg */ 9001e04c3fSmrgclass ir_array_reference_visitor : public ir_hierarchical_visitor { 9101e04c3fSmrgpublic: 9201e04c3fSmrg ir_array_reference_visitor(void) 9301e04c3fSmrg { 9401e04c3fSmrg this->mem_ctx = ralloc_context(NULL); 9501e04c3fSmrg this->variable_list.make_empty(); 9601e04c3fSmrg this->in_whole_array_copy = false; 9701e04c3fSmrg } 9801e04c3fSmrg 9901e04c3fSmrg ~ir_array_reference_visitor(void) 10001e04c3fSmrg { 10101e04c3fSmrg ralloc_free(mem_ctx); 10201e04c3fSmrg } 10301e04c3fSmrg 10401e04c3fSmrg bool get_split_list(exec_list *instructions, bool linked); 10501e04c3fSmrg 10601e04c3fSmrg virtual ir_visitor_status visit(ir_variable *); 10701e04c3fSmrg virtual ir_visitor_status visit(ir_dereference_variable *); 10801e04c3fSmrg virtual ir_visitor_status visit_enter(ir_assignment *); 10901e04c3fSmrg virtual ir_visitor_status visit_leave(ir_assignment *); 11001e04c3fSmrg virtual ir_visitor_status visit_enter(ir_dereference_array *); 11101e04c3fSmrg virtual ir_visitor_status visit_enter(ir_function_signature *); 11201e04c3fSmrg 11301e04c3fSmrg variable_entry *get_variable_entry(ir_variable *var); 11401e04c3fSmrg 11501e04c3fSmrg /* List of variable_entry */ 11601e04c3fSmrg exec_list variable_list; 11701e04c3fSmrg 11801e04c3fSmrg void *mem_ctx; 11901e04c3fSmrg 12001e04c3fSmrg bool in_whole_array_copy; 12101e04c3fSmrg}; 12201e04c3fSmrg 12301e04c3fSmrg} /* namespace */ 12401e04c3fSmrg 12501e04c3fSmrgvariable_entry * 12601e04c3fSmrgir_array_reference_visitor::get_variable_entry(ir_variable *var) 12701e04c3fSmrg{ 12801e04c3fSmrg assert(var); 12901e04c3fSmrg 13001e04c3fSmrg if (var->data.mode != ir_var_auto && 13101e04c3fSmrg var->data.mode != ir_var_temporary) 13201e04c3fSmrg return NULL; 13301e04c3fSmrg 13401e04c3fSmrg if (!(var->type->is_array() || var->type->is_matrix())) 13501e04c3fSmrg return NULL; 13601e04c3fSmrg 13701e04c3fSmrg /* If the array hasn't been sized yet, we can't split it. After 13801e04c3fSmrg * linking, this should be resolved. 13901e04c3fSmrg */ 14001e04c3fSmrg if (var->type->is_unsized_array()) 14101e04c3fSmrg return NULL; 14201e04c3fSmrg 14301e04c3fSmrg /* FIXME: arrays of arrays are not handled correctly by this pass so we 14401e04c3fSmrg * skip it for now. While the pass will create functioning code it actually 14501e04c3fSmrg * produces worse code. 14601e04c3fSmrg * 14701e04c3fSmrg * For example the array: 14801e04c3fSmrg * 14901e04c3fSmrg * int[3][2] a; 15001e04c3fSmrg * 15101e04c3fSmrg * ends up being split up into: 15201e04c3fSmrg * 15301e04c3fSmrg * int[3][2] a_0; 15401e04c3fSmrg * int[3][2] a_1; 15501e04c3fSmrg * int[3][2] a_2; 15601e04c3fSmrg * 15701e04c3fSmrg * And we end up referencing each of these new arrays for example: 15801e04c3fSmrg * 15901e04c3fSmrg * a[0][1] will be turned into a_0[0][1] 16001e04c3fSmrg * a[1][0] will be turned into a_1[1][0] 16101e04c3fSmrg * a[2][0] will be turned into a_2[2][0] 16201e04c3fSmrg */ 16301e04c3fSmrg if (var->type->is_array() && var->type->fields.array->is_array()) 16401e04c3fSmrg return NULL; 16501e04c3fSmrg 16601e04c3fSmrg foreach_in_list(variable_entry, entry, &this->variable_list) { 16701e04c3fSmrg if (entry->var == var) 16801e04c3fSmrg return entry; 16901e04c3fSmrg } 17001e04c3fSmrg 17101e04c3fSmrg variable_entry *entry = new(mem_ctx) variable_entry(var); 17201e04c3fSmrg this->variable_list.push_tail(entry); 17301e04c3fSmrg return entry; 17401e04c3fSmrg} 17501e04c3fSmrg 17601e04c3fSmrg 17701e04c3fSmrgir_visitor_status 17801e04c3fSmrgir_array_reference_visitor::visit(ir_variable *ir) 17901e04c3fSmrg{ 18001e04c3fSmrg variable_entry *entry = this->get_variable_entry(ir); 18101e04c3fSmrg 18201e04c3fSmrg if (entry) 18301e04c3fSmrg entry->declaration = true; 18401e04c3fSmrg 18501e04c3fSmrg return visit_continue; 18601e04c3fSmrg} 18701e04c3fSmrg 18801e04c3fSmrgir_visitor_status 18901e04c3fSmrgir_array_reference_visitor::visit_enter(ir_assignment *ir) 19001e04c3fSmrg{ 19101e04c3fSmrg in_whole_array_copy = 19201e04c3fSmrg ir->lhs->type->is_array() && ir->whole_variable_written(); 19301e04c3fSmrg 19401e04c3fSmrg return visit_continue; 19501e04c3fSmrg} 19601e04c3fSmrg 19701e04c3fSmrgir_visitor_status 19801e04c3fSmrgir_array_reference_visitor::visit_leave(ir_assignment *) 19901e04c3fSmrg{ 20001e04c3fSmrg in_whole_array_copy = false; 20101e04c3fSmrg 20201e04c3fSmrg return visit_continue; 20301e04c3fSmrg} 20401e04c3fSmrg 20501e04c3fSmrgir_visitor_status 20601e04c3fSmrgir_array_reference_visitor::visit(ir_dereference_variable *ir) 20701e04c3fSmrg{ 20801e04c3fSmrg variable_entry *entry = this->get_variable_entry(ir->var); 20901e04c3fSmrg 21001e04c3fSmrg /* Allow whole-array assignments on the LHS. We can split those 21101e04c3fSmrg * by "unrolling" the assignment into component-wise assignments. 21201e04c3fSmrg */ 21301e04c3fSmrg if (in_assignee && in_whole_array_copy) 21401e04c3fSmrg return visit_continue; 21501e04c3fSmrg 21601e04c3fSmrg /* If we made it to here without seeing an ir_dereference_array, 21701e04c3fSmrg * then the dereference of this array didn't have a constant index 21801e04c3fSmrg * (see the visit_continue_with_parent below), so we can't split 21901e04c3fSmrg * the variable. 22001e04c3fSmrg */ 22101e04c3fSmrg if (entry) 22201e04c3fSmrg entry->split = false; 22301e04c3fSmrg 22401e04c3fSmrg return visit_continue; 22501e04c3fSmrg} 22601e04c3fSmrg 22701e04c3fSmrgir_visitor_status 22801e04c3fSmrgir_array_reference_visitor::visit_enter(ir_dereference_array *ir) 22901e04c3fSmrg{ 23001e04c3fSmrg ir_dereference_variable *deref = ir->array->as_dereference_variable(); 23101e04c3fSmrg if (!deref) 23201e04c3fSmrg return visit_continue; 23301e04c3fSmrg 23401e04c3fSmrg variable_entry *entry = this->get_variable_entry(deref->var); 23501e04c3fSmrg 23601e04c3fSmrg /* If the access to the array has a variable index, we wouldn't 23701e04c3fSmrg * know which split variable this dereference should go to. 23801e04c3fSmrg */ 23901e04c3fSmrg if (!ir->array_index->as_constant()) { 24001e04c3fSmrg if (entry) 24101e04c3fSmrg entry->split = false; 24201e04c3fSmrg /* This variable indexing could come from a different array dereference 24301e04c3fSmrg * that also has variable indexing, that is, something like a[b[a[b[0]]]]. 24401e04c3fSmrg * If we return visit_continue_with_parent here for the first appearence 24501e04c3fSmrg * of a, then we can miss that b also has indirect indexing (if this is 24601e04c3fSmrg * the only place in the program where such indirect indexing into b 24701e04c3fSmrg * happens), so keep going. 24801e04c3fSmrg */ 24901e04c3fSmrg return visit_continue; 25001e04c3fSmrg } 25101e04c3fSmrg 25201e04c3fSmrg /* If the index is also array dereference, visit index. */ 25301e04c3fSmrg if (ir->array_index->as_dereference_array()) 25401e04c3fSmrg visit_enter(ir->array_index->as_dereference_array()); 25501e04c3fSmrg 25601e04c3fSmrg return visit_continue_with_parent; 25701e04c3fSmrg} 25801e04c3fSmrg 25901e04c3fSmrgir_visitor_status 26001e04c3fSmrgir_array_reference_visitor::visit_enter(ir_function_signature *ir) 26101e04c3fSmrg{ 26201e04c3fSmrg /* We don't have logic for array-splitting function arguments, 26301e04c3fSmrg * so just look at the body instructions and not the parameter 26401e04c3fSmrg * declarations. 26501e04c3fSmrg */ 26601e04c3fSmrg visit_list_elements(this, &ir->body); 26701e04c3fSmrg return visit_continue_with_parent; 26801e04c3fSmrg} 26901e04c3fSmrg 27001e04c3fSmrgbool 27101e04c3fSmrgir_array_reference_visitor::get_split_list(exec_list *instructions, 27201e04c3fSmrg bool linked) 27301e04c3fSmrg{ 27401e04c3fSmrg visit_list_elements(this, instructions); 27501e04c3fSmrg 27601e04c3fSmrg /* If the shaders aren't linked yet, we can't mess with global 27701e04c3fSmrg * declarations, which need to be matched by name across shaders. 27801e04c3fSmrg */ 27901e04c3fSmrg if (!linked) { 28001e04c3fSmrg foreach_in_list(ir_instruction, node, instructions) { 28101e04c3fSmrg ir_variable *var = node->as_variable(); 28201e04c3fSmrg if (var) { 28301e04c3fSmrg variable_entry *entry = get_variable_entry(var); 28401e04c3fSmrg if (entry) 28501e04c3fSmrg entry->remove(); 28601e04c3fSmrg } 28701e04c3fSmrg } 28801e04c3fSmrg } 28901e04c3fSmrg 29001e04c3fSmrg /* Trim out variables we found that we can't split. */ 29101e04c3fSmrg foreach_in_list_safe(variable_entry, entry, &variable_list) { 29201e04c3fSmrg if (debug) { 29301e04c3fSmrg printf("array %s@%p: decl %d, split %d\n", 29401e04c3fSmrg entry->var->name, (void *) entry->var, entry->declaration, 29501e04c3fSmrg entry->split); 29601e04c3fSmrg } 29701e04c3fSmrg 29801e04c3fSmrg if (!(entry->declaration && entry->split)) { 29901e04c3fSmrg entry->remove(); 30001e04c3fSmrg } 30101e04c3fSmrg } 30201e04c3fSmrg 30301e04c3fSmrg return !variable_list.is_empty(); 30401e04c3fSmrg} 30501e04c3fSmrg 30601e04c3fSmrg/** 30701e04c3fSmrg * This class rewrites the dereferences of arrays that have been split 30801e04c3fSmrg * to use the newly created ir_variables for each component. 30901e04c3fSmrg */ 31001e04c3fSmrgclass ir_array_splitting_visitor : public ir_rvalue_visitor { 31101e04c3fSmrgpublic: 31201e04c3fSmrg ir_array_splitting_visitor(exec_list *vars) 31301e04c3fSmrg { 31401e04c3fSmrg this->variable_list = vars; 31501e04c3fSmrg } 31601e04c3fSmrg 31701e04c3fSmrg virtual ~ir_array_splitting_visitor() 31801e04c3fSmrg { 31901e04c3fSmrg } 32001e04c3fSmrg 32101e04c3fSmrg virtual ir_visitor_status visit_leave(ir_assignment *); 32201e04c3fSmrg 32301e04c3fSmrg void split_deref(ir_dereference **deref); 32401e04c3fSmrg void handle_rvalue(ir_rvalue **rvalue); 32501e04c3fSmrg variable_entry *get_splitting_entry(ir_variable *var); 32601e04c3fSmrg 32701e04c3fSmrg exec_list *variable_list; 32801e04c3fSmrg}; 32901e04c3fSmrg 33001e04c3fSmrgvariable_entry * 33101e04c3fSmrgir_array_splitting_visitor::get_splitting_entry(ir_variable *var) 33201e04c3fSmrg{ 33301e04c3fSmrg assert(var); 33401e04c3fSmrg 33501e04c3fSmrg foreach_in_list(variable_entry, entry, this->variable_list) { 33601e04c3fSmrg if (entry->var == var) { 33701e04c3fSmrg return entry; 33801e04c3fSmrg } 33901e04c3fSmrg } 34001e04c3fSmrg 34101e04c3fSmrg return NULL; 34201e04c3fSmrg} 34301e04c3fSmrg 34401e04c3fSmrgvoid 34501e04c3fSmrgir_array_splitting_visitor::split_deref(ir_dereference **deref) 34601e04c3fSmrg{ 34701e04c3fSmrg ir_dereference_array *deref_array = (*deref)->as_dereference_array(); 34801e04c3fSmrg if (!deref_array) 34901e04c3fSmrg return; 35001e04c3fSmrg 35101e04c3fSmrg ir_dereference_variable *deref_var = deref_array->array->as_dereference_variable(); 35201e04c3fSmrg if (!deref_var) 35301e04c3fSmrg return; 35401e04c3fSmrg ir_variable *var = deref_var->var; 35501e04c3fSmrg 35601e04c3fSmrg variable_entry *entry = get_splitting_entry(var); 35701e04c3fSmrg if (!entry) 35801e04c3fSmrg return; 35901e04c3fSmrg 36001e04c3fSmrg ir_constant *constant = deref_array->array_index->as_constant(); 36101e04c3fSmrg assert(constant); 36201e04c3fSmrg 36301e04c3fSmrg if (constant->value.i[0] >= 0 && constant->value.i[0] < (int)entry->size) { 36401e04c3fSmrg *deref = new(entry->mem_ctx) 36501e04c3fSmrg ir_dereference_variable(entry->components[constant->value.i[0]]); 36601e04c3fSmrg } else { 36701e04c3fSmrg /* There was a constant array access beyond the end of the 36801e04c3fSmrg * array. This might have happened due to constant folding 36901e04c3fSmrg * after the initial parse. This produces an undefined value, 37001e04c3fSmrg * but shouldn't crash. Just give them an uninitialized 37101e04c3fSmrg * variable. 37201e04c3fSmrg */ 37301e04c3fSmrg ir_variable *temp = new(entry->mem_ctx) ir_variable(deref_array->type, 37401e04c3fSmrg "undef", 37501e04c3fSmrg ir_var_temporary); 37601e04c3fSmrg entry->components[0]->insert_before(temp); 37701e04c3fSmrg *deref = new(entry->mem_ctx) ir_dereference_variable(temp); 37801e04c3fSmrg } 37901e04c3fSmrg} 38001e04c3fSmrg 38101e04c3fSmrgvoid 38201e04c3fSmrgir_array_splitting_visitor::handle_rvalue(ir_rvalue **rvalue) 38301e04c3fSmrg{ 38401e04c3fSmrg if (!*rvalue) 38501e04c3fSmrg return; 38601e04c3fSmrg 38701e04c3fSmrg ir_dereference *deref = (*rvalue)->as_dereference(); 38801e04c3fSmrg 38901e04c3fSmrg if (!deref) 39001e04c3fSmrg return; 39101e04c3fSmrg 39201e04c3fSmrg split_deref(&deref); 39301e04c3fSmrg *rvalue = deref; 39401e04c3fSmrg} 39501e04c3fSmrg 39601e04c3fSmrgir_visitor_status 39701e04c3fSmrgir_array_splitting_visitor::visit_leave(ir_assignment *ir) 39801e04c3fSmrg{ 39901e04c3fSmrg /* The normal rvalue visitor skips the LHS of assignments, but we 40001e04c3fSmrg * need to process those just the same. 40101e04c3fSmrg */ 40201e04c3fSmrg ir_rvalue *lhs = ir->lhs; 40301e04c3fSmrg 40401e04c3fSmrg /* "Unroll" any whole array assignments, creating assignments for 40501e04c3fSmrg * each array element. Then, do splitting on each new assignment. 40601e04c3fSmrg */ 40701e04c3fSmrg if (lhs->type->is_array() && ir->whole_variable_written() && 40801e04c3fSmrg get_splitting_entry(ir->whole_variable_written())) { 40901e04c3fSmrg void *mem_ctx = ralloc_parent(ir); 41001e04c3fSmrg 41101e04c3fSmrg for (unsigned i = 0; i < lhs->type->length; i++) { 41201e04c3fSmrg ir_rvalue *lhs_i = 41301e04c3fSmrg new(mem_ctx) ir_dereference_array(ir->lhs->clone(mem_ctx, NULL), 41401e04c3fSmrg new(mem_ctx) ir_constant(i)); 41501e04c3fSmrg ir_rvalue *rhs_i = 41601e04c3fSmrg new(mem_ctx) ir_dereference_array(ir->rhs->clone(mem_ctx, NULL), 41701e04c3fSmrg new(mem_ctx) ir_constant(i)); 41801e04c3fSmrg ir_rvalue *condition_i = 41901e04c3fSmrg ir->condition ? ir->condition->clone(mem_ctx, NULL) : NULL; 42001e04c3fSmrg 42101e04c3fSmrg ir_assignment *assign_i = 42201e04c3fSmrg new(mem_ctx) ir_assignment(lhs_i, rhs_i, condition_i); 42301e04c3fSmrg 42401e04c3fSmrg ir->insert_before(assign_i); 42501e04c3fSmrg assign_i->accept(this); 42601e04c3fSmrg } 42701e04c3fSmrg ir->remove(); 42801e04c3fSmrg return visit_continue; 42901e04c3fSmrg } 43001e04c3fSmrg 43101e04c3fSmrg handle_rvalue(&lhs); 43201e04c3fSmrg ir->lhs = lhs->as_dereference(); 43301e04c3fSmrg 43401e04c3fSmrg ir->lhs->accept(this); 43501e04c3fSmrg 43601e04c3fSmrg handle_rvalue(&ir->rhs); 43701e04c3fSmrg ir->rhs->accept(this); 43801e04c3fSmrg 43901e04c3fSmrg if (ir->condition) { 44001e04c3fSmrg handle_rvalue(&ir->condition); 44101e04c3fSmrg ir->condition->accept(this); 44201e04c3fSmrg } 44301e04c3fSmrg 44401e04c3fSmrg return visit_continue; 44501e04c3fSmrg} 44601e04c3fSmrg 44701e04c3fSmrgbool 44801e04c3fSmrgoptimize_split_arrays(exec_list *instructions, bool linked) 44901e04c3fSmrg{ 45001e04c3fSmrg ir_array_reference_visitor refs; 45101e04c3fSmrg if (!refs.get_split_list(instructions, linked)) 45201e04c3fSmrg return false; 45301e04c3fSmrg 45401e04c3fSmrg void *mem_ctx = ralloc_context(NULL); 45501e04c3fSmrg 45601e04c3fSmrg /* Replace the decls of the arrays to be split with their split 45701e04c3fSmrg * components. 45801e04c3fSmrg */ 45901e04c3fSmrg foreach_in_list(variable_entry, entry, &refs.variable_list) { 46001e04c3fSmrg const struct glsl_type *type = entry->var->type; 46101e04c3fSmrg const struct glsl_type *subtype; 46201e04c3fSmrg 46301e04c3fSmrg if (type->is_matrix()) 46401e04c3fSmrg subtype = type->column_type(); 46501e04c3fSmrg else 46601e04c3fSmrg subtype = type->fields.array; 46701e04c3fSmrg 46801e04c3fSmrg entry->mem_ctx = ralloc_parent(entry->var); 46901e04c3fSmrg 47001e04c3fSmrg entry->components = ralloc_array(mem_ctx, ir_variable *, entry->size); 47101e04c3fSmrg 47201e04c3fSmrg for (unsigned int i = 0; i < entry->size; i++) { 47301e04c3fSmrg const char *name = ralloc_asprintf(mem_ctx, "%s_%d", 47401e04c3fSmrg entry->var->name, i); 47501e04c3fSmrg ir_variable *new_var = 47601e04c3fSmrg new(entry->mem_ctx) ir_variable(subtype, name, ir_var_temporary); 4777ec681f3Smrg new_var->data.invariant = entry->var->data.invariant; 4787ec681f3Smrg new_var->data.precise = entry->var->data.precise; 47901e04c3fSmrg 48001e04c3fSmrg /* Do not lose memory/format qualifiers when arrays of images are 48101e04c3fSmrg * split. 48201e04c3fSmrg */ 48301e04c3fSmrg new_var->data.memory_read_only = entry->var->data.memory_read_only; 48401e04c3fSmrg new_var->data.memory_write_only = entry->var->data.memory_write_only; 48501e04c3fSmrg new_var->data.memory_coherent = entry->var->data.memory_coherent; 48601e04c3fSmrg new_var->data.memory_volatile = entry->var->data.memory_volatile; 48701e04c3fSmrg new_var->data.memory_restrict = entry->var->data.memory_restrict; 48801e04c3fSmrg new_var->data.image_format = entry->var->data.image_format; 48901e04c3fSmrg 49001e04c3fSmrg entry->components[i] = new_var; 49101e04c3fSmrg entry->var->insert_before(entry->components[i]); 49201e04c3fSmrg } 49301e04c3fSmrg 49401e04c3fSmrg entry->var->remove(); 49501e04c3fSmrg } 49601e04c3fSmrg 49701e04c3fSmrg ir_array_splitting_visitor split(&refs.variable_list); 49801e04c3fSmrg visit_list_elements(&split, instructions); 49901e04c3fSmrg 50001e04c3fSmrg if (debug) 50101e04c3fSmrg _mesa_print_ir(stdout, instructions, NULL); 50201e04c3fSmrg 50301e04c3fSmrg ralloc_free(mem_ctx); 50401e04c3fSmrg 50501e04c3fSmrg return true; 50601e04c3fSmrg 50701e04c3fSmrg} 508