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