160177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt/*
260177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt * Copyright © 2010 Intel Corporation
360177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt *
460177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt * Permission is hereby granted, free of charge, to any person obtaining a
560177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt * copy of this software and associated documentation files (the "Software"),
660177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt * to deal in the Software without restriction, including without limitation
760177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt * the rights to use, copy, modify, merge, publish, distribute, sublicense,
860177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt * and/or sell copies of the Software, and to permit persons to whom the
960177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt * Software is furnished to do so, subject to the following conditions:
1060177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt *
1160177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt * The above copyright notice and this permission notice (including the next
1260177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt * paragraph) shall be included in all copies or substantial portions of the
1360177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt * Software.
1460177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt *
1560177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1660177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1760177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
1860177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1960177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
2060177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
2160177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt * DEALINGS IN THE SOFTWARE.
2260177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt */
2360177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt
2460177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt/**
2560177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt * \file opt_array_splitting.cpp
2660177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt *
2760177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt * If an array is always dereferenced with a constant index, then
2860177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt * split it apart into its elements, making it more amenable to other
2960177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt * optimization passes.
3060177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt *
3160177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt * This skips uniform/varying arrays, which would need careful
3260177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt * handling due to their ir->location fields tying them to the GL API
3360177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt * and other shader stages.
3460177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt */
3560177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt
3660177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt#include "ir.h"
3760177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt#include "ir_visitor.h"
3860177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt#include "ir_rvalue_visitor.h"
3960177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt#include "ir_print_visitor.h"
4060177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt#include "glsl_types.h"
4160177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt
4260177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholtstatic bool debug = false;
4360177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt
4460177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholtnamespace opt_array_splitting {
4560177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt
4660177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholtclass variable_entry : public exec_node
4760177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt{
4860177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholtpublic:
4960177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt   variable_entry(ir_variable *var)
5060177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt   {
5160177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt      this->var = var;
52538ba0a36373d7d0bd047e6fc4ef4e6e8d8bb8d7Eric Anholt      this->split = true;
5360177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt      this->declaration = false;
5460177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt      this->components = NULL;
5560177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt      this->mem_ctx = NULL;
563bdccbc3e0185fbca16eada2a76f55c6e3f867b5Eric Anholt      if (var->type->is_array())
573bdccbc3e0185fbca16eada2a76f55c6e3f867b5Eric Anholt	 this->size = var->type->length;
583bdccbc3e0185fbca16eada2a76f55c6e3f867b5Eric Anholt      else
593bdccbc3e0185fbca16eada2a76f55c6e3f867b5Eric Anholt	 this->size = var->type->matrix_columns;
6060177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt   }
6160177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt
6260177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt   ir_variable *var; /* The key: the variable's pointer. */
633bdccbc3e0185fbca16eada2a76f55c6e3f867b5Eric Anholt   unsigned size; /* array length or matrix columns */
6460177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt
65538ba0a36373d7d0bd047e6fc4ef4e6e8d8bb8d7Eric Anholt   /** Whether this array should be split or not. */
66538ba0a36373d7d0bd047e6fc4ef4e6e8d8bb8d7Eric Anholt   bool split;
6760177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt
686de5da079682efd3f8887d3e0a7add7e70a5433dEric Anholt   /* If the variable had a decl we can work with in the instruction
696de5da079682efd3f8887d3e0a7add7e70a5433dEric Anholt    * stream.  We can't do splitting on function arguments, which
706de5da079682efd3f8887d3e0a7add7e70a5433dEric Anholt    * don't get this variable set.
716de5da079682efd3f8887d3e0a7add7e70a5433dEric Anholt    */
726de5da079682efd3f8887d3e0a7add7e70a5433dEric Anholt   bool declaration;
7360177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt
7460177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt   ir_variable **components;
7560177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt
7660177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt   /** ralloc_parent(this->var) -- the shader's talloc context. */
7760177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt   void *mem_ctx;
7860177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt};
7960177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt
8060177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt} /* namespace */
8160177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholtusing namespace opt_array_splitting;
8260177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt
8360177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt/**
8460177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt * This class does a walk over the tree, coming up with the set of
8560177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt * variables that could be split by looking to see if they are arrays
8660177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt * that are only ever constant-index dereferenced.
8760177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt */
8860177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholtclass ir_array_reference_visitor : public ir_hierarchical_visitor {
8960177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholtpublic:
9060177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt   ir_array_reference_visitor(void)
9160177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt   {
9260177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt      this->mem_ctx = ralloc_context(NULL);
9360177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt      this->variable_list.make_empty();
9460177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt   }
9560177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt
9660177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt   ~ir_array_reference_visitor(void)
9760177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt   {
9860177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt      ralloc_free(mem_ctx);
9960177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt   }
10060177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt
10160177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt   bool get_split_list(exec_list *instructions, bool linked);
10260177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt
10360177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt   virtual ir_visitor_status visit(ir_variable *);
10460177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt   virtual ir_visitor_status visit(ir_dereference_variable *);
10560177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt   virtual ir_visitor_status visit_enter(ir_dereference_array *);
1066de5da079682efd3f8887d3e0a7add7e70a5433dEric Anholt   virtual ir_visitor_status visit_enter(ir_function_signature *);
10760177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt
10860177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt   variable_entry *get_variable_entry(ir_variable *var);
10960177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt
11060177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt   /* List of variable_entry */
11160177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt   exec_list variable_list;
11260177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt
11360177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt   void *mem_ctx;
11460177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt};
11560177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt
11660177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholtvariable_entry *
11760177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholtir_array_reference_visitor::get_variable_entry(ir_variable *var)
11860177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt{
11960177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt   assert(var);
12060177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt
12160177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt   if (var->mode != ir_var_auto &&
12260177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt       var->mode != ir_var_temporary)
12360177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt      return NULL;
12460177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt
1253bdccbc3e0185fbca16eada2a76f55c6e3f867b5Eric Anholt   if (!(var->type->is_array() || var->type->is_matrix()))
12660177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt      return NULL;
12760177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt
12860177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt   /* If the array hasn't been sized yet, we can't split it.  After
12960177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt    * linking, this should be resolved.
13060177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt    */
1313bdccbc3e0185fbca16eada2a76f55c6e3f867b5Eric Anholt   if (var->type->is_array() && var->type->length == 0)
13260177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt      return NULL;
13360177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt
13460177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt   foreach_iter(exec_list_iterator, iter, this->variable_list) {
13560177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt      variable_entry *entry = (variable_entry *)iter.get();
13660177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt      if (entry->var == var)
13760177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt	 return entry;
13860177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt   }
13960177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt
14060177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt   variable_entry *entry = new(mem_ctx) variable_entry(var);
14160177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt   this->variable_list.push_tail(entry);
14260177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt   return entry;
14360177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt}
14460177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt
14560177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt
14660177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholtir_visitor_status
14760177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholtir_array_reference_visitor::visit(ir_variable *ir)
14860177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt{
14960177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt   variable_entry *entry = this->get_variable_entry(ir);
15060177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt
15160177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt   if (entry)
15260177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt      entry->declaration = true;
15360177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt
15460177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt   return visit_continue;
15560177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt}
15660177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt
15760177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholtir_visitor_status
15860177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholtir_array_reference_visitor::visit(ir_dereference_variable *ir)
15960177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt{
16060177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt   variable_entry *entry = this->get_variable_entry(ir->var);
16160177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt
162538ba0a36373d7d0bd047e6fc4ef4e6e8d8bb8d7Eric Anholt   /* If we made it to here without seeing an ir_dereference_array,
163538ba0a36373d7d0bd047e6fc4ef4e6e8d8bb8d7Eric Anholt    * then the dereference of this array didn't have a constant index
164538ba0a36373d7d0bd047e6fc4ef4e6e8d8bb8d7Eric Anholt    * (see the visit_continue_with_parent below), so we can't split
165538ba0a36373d7d0bd047e6fc4ef4e6e8d8bb8d7Eric Anholt    * the variable.
16660177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt    */
16760177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt   if (entry)
168538ba0a36373d7d0bd047e6fc4ef4e6e8d8bb8d7Eric Anholt      entry->split = false;
16960177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt
17060177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt   return visit_continue;
17160177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt}
17260177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt
17360177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholtir_visitor_status
17460177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholtir_array_reference_visitor::visit_enter(ir_dereference_array *ir)
17560177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt{
17660177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt   ir_dereference_variable *deref = ir->array->as_dereference_variable();
17760177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt   if (!deref)
17860177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt      return visit_continue;
17960177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt
18060177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt   variable_entry *entry = this->get_variable_entry(deref->var);
18160177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt
182538ba0a36373d7d0bd047e6fc4ef4e6e8d8bb8d7Eric Anholt   /* If the access to the array has a variable index, we wouldn't
183538ba0a36373d7d0bd047e6fc4ef4e6e8d8bb8d7Eric Anholt    * know which split variable this dereference should go to.
184538ba0a36373d7d0bd047e6fc4ef4e6e8d8bb8d7Eric Anholt    */
18560177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt   if (entry && !ir->array_index->as_constant())
186538ba0a36373d7d0bd047e6fc4ef4e6e8d8bb8d7Eric Anholt      entry->split = false;
18760177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt
18860177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt   return visit_continue_with_parent;
18960177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt}
19060177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt
1916de5da079682efd3f8887d3e0a7add7e70a5433dEric Anholtir_visitor_status
1926de5da079682efd3f8887d3e0a7add7e70a5433dEric Anholtir_array_reference_visitor::visit_enter(ir_function_signature *ir)
1936de5da079682efd3f8887d3e0a7add7e70a5433dEric Anholt{
1946de5da079682efd3f8887d3e0a7add7e70a5433dEric Anholt   /* We don't have logic for array-splitting function arguments,
1956de5da079682efd3f8887d3e0a7add7e70a5433dEric Anholt    * so just look at the body instructions and not the parameter
1966de5da079682efd3f8887d3e0a7add7e70a5433dEric Anholt    * declarations.
1976de5da079682efd3f8887d3e0a7add7e70a5433dEric Anholt    */
1986de5da079682efd3f8887d3e0a7add7e70a5433dEric Anholt   visit_list_elements(this, &ir->body);
1996de5da079682efd3f8887d3e0a7add7e70a5433dEric Anholt   return visit_continue_with_parent;
2006de5da079682efd3f8887d3e0a7add7e70a5433dEric Anholt}
2016de5da079682efd3f8887d3e0a7add7e70a5433dEric Anholt
20260177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholtbool
20360177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholtir_array_reference_visitor::get_split_list(exec_list *instructions,
20460177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt					   bool linked)
20560177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt{
20660177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt   visit_list_elements(this, instructions);
20760177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt
20860177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt   /* If the shaders aren't linked yet, we can't mess with global
20960177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt    * declarations, which need to be matched by name across shaders.
21060177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt    */
21160177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt   if (!linked) {
21260177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt      foreach_list(node, instructions) {
21360177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt	 ir_variable *var = ((ir_instruction *)node)->as_variable();
21460177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt	 if (var) {
21560177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt	    variable_entry *entry = get_variable_entry(var);
21660177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt	    if (entry)
21760177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt	       entry->remove();
21860177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt	 }
21960177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt      }
22060177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt   }
22160177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt
22260177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt   /* Trim out variables we found that we can't split. */
22360177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt   foreach_iter(exec_list_iterator, iter, variable_list) {
22460177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt      variable_entry *entry = (variable_entry *)iter.get();
22560177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt
22660177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt      if (debug) {
227538ba0a36373d7d0bd047e6fc4ef4e6e8d8bb8d7Eric Anholt	 printf("array %s@%p: decl %d, split %d\n",
22860177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt		entry->var->name, (void *) entry->var, entry->declaration,
229538ba0a36373d7d0bd047e6fc4ef4e6e8d8bb8d7Eric Anholt		entry->split);
23060177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt      }
23160177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt
232538ba0a36373d7d0bd047e6fc4ef4e6e8d8bb8d7Eric Anholt      if (!(entry->declaration && entry->split)) {
23360177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt	 entry->remove();
23460177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt      }
23560177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt   }
23660177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt
23760177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt   return !variable_list.is_empty();
23860177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt}
23960177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt
24036a8c9caafef79524920120286649a0f53fe5228Eric Anholt/**
24136a8c9caafef79524920120286649a0f53fe5228Eric Anholt * This class rewrites the dereferences of arrays that have been split
24236a8c9caafef79524920120286649a0f53fe5228Eric Anholt * to use the newly created ir_variables for each component.
24336a8c9caafef79524920120286649a0f53fe5228Eric Anholt */
24460177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholtclass ir_array_splitting_visitor : public ir_rvalue_visitor {
24560177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholtpublic:
24660177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt   ir_array_splitting_visitor(exec_list *vars)
24760177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt   {
24860177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt      this->variable_list = vars;
24960177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt   }
25060177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt
25160177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt   virtual ~ir_array_splitting_visitor()
25260177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt   {
25360177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt   }
25460177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt
25560177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt   virtual ir_visitor_status visit_leave(ir_assignment *);
25660177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt
25760177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt   void split_deref(ir_dereference **deref);
25860177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt   void handle_rvalue(ir_rvalue **rvalue);
25960177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt   variable_entry *get_splitting_entry(ir_variable *var);
26060177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt
26160177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt   exec_list *variable_list;
26260177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt};
26360177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt
26460177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholtvariable_entry *
26560177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholtir_array_splitting_visitor::get_splitting_entry(ir_variable *var)
26660177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt{
26760177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt   assert(var);
26860177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt
26960177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt   foreach_iter(exec_list_iterator, iter, *this->variable_list) {
27060177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt      variable_entry *entry = (variable_entry *)iter.get();
27160177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt      if (entry->var == var) {
27260177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt	 return entry;
27360177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt      }
27460177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt   }
27560177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt
27660177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt   return NULL;
27760177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt}
27860177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt
27960177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholtvoid
28060177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholtir_array_splitting_visitor::split_deref(ir_dereference **deref)
28160177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt{
28260177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt   ir_dereference_array *deref_array = (*deref)->as_dereference_array();
28360177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt   if (!deref_array)
28460177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt      return;
28560177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt
28660177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt   ir_dereference_variable *deref_var = deref_array->array->as_dereference_variable();
28760177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt   if (!deref_var)
28860177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt      return;
28960177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt   ir_variable *var = deref_var->var;
29060177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt
29160177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt   variable_entry *entry = get_splitting_entry(var);
29260177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt   if (!entry)
29360177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt      return;
29460177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt
29560177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt   ir_constant *constant = deref_array->array_index->as_constant();
29660177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt   assert(constant);
29760177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt
2983bdccbc3e0185fbca16eada2a76f55c6e3f867b5Eric Anholt   if (constant->value.i[0] < (int)entry->size) {
29960177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt      *deref = new(entry->mem_ctx)
30060177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt	 ir_dereference_variable(entry->components[constant->value.i[0]]);
30160177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt   } else {
30260177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt      /* There was a constant array access beyond the end of the
30360177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt       * array.  This might have happened due to constant folding
30460177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt       * after the initial parse.  This produces an undefined value,
30560177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt       * but shouldn't crash.  Just give them an uninitialized
30660177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt       * variable.
30760177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt       */
30860177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt      ir_variable *temp = new(entry->mem_ctx) ir_variable(deref_array->type,
30960177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt							  "undef",
31060177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt							  ir_var_temporary);
31160177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt      entry->components[0]->insert_before(temp);
31260177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt      *deref = new(entry->mem_ctx) ir_dereference_variable(temp);
31360177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt   }
31460177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt}
31560177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt
31660177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholtvoid
31760177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholtir_array_splitting_visitor::handle_rvalue(ir_rvalue **rvalue)
31860177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt{
31960177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt   if (!*rvalue)
32060177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt      return;
32160177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt
32260177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt   ir_dereference *deref = (*rvalue)->as_dereference();
32360177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt
32460177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt   if (!deref)
32560177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt      return;
32660177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt
32760177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt   split_deref(&deref);
32860177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt   *rvalue = deref;
32960177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt}
33060177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt
33160177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholtir_visitor_status
33260177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholtir_array_splitting_visitor::visit_leave(ir_assignment *ir)
33360177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt{
33460177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt   /* The normal rvalue visitor skips the LHS of assignments, but we
33560177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt    * need to process those just the same.
33660177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt    */
33760177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt   ir_rvalue *lhs = ir->lhs;
33860177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt
33960177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt   handle_rvalue(&lhs);
34060177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt   ir->lhs = lhs->as_dereference();
34160177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt
34260177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt   ir->lhs->accept(this);
34360177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt
34460177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt   handle_rvalue(&ir->rhs);
34560177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt   ir->rhs->accept(this);
34660177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt
34760177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt   if (ir->condition) {
34860177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt      handle_rvalue(&ir->condition);
34960177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt      ir->condition->accept(this);
35060177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt   }
35160177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt
35260177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt   return visit_continue;
35360177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt}
35460177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt
35560177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholtbool
35660177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholtoptimize_split_arrays(exec_list *instructions, bool linked)
35760177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt{
35860177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt   ir_array_reference_visitor refs;
35960177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt   if (!refs.get_split_list(instructions, linked))
36060177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt      return false;
36160177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt
36260177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt   void *mem_ctx = ralloc_context(NULL);
36360177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt
36460177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt   /* Replace the decls of the arrays to be split with their split
36560177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt    * components.
36660177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt    */
36760177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt   foreach_iter(exec_list_iterator, iter, refs.variable_list) {
36860177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt      variable_entry *entry = (variable_entry *)iter.get();
36960177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt      const struct glsl_type *type = entry->var->type;
3703bdccbc3e0185fbca16eada2a76f55c6e3f867b5Eric Anholt      const struct glsl_type *subtype;
3713bdccbc3e0185fbca16eada2a76f55c6e3f867b5Eric Anholt
3723bdccbc3e0185fbca16eada2a76f55c6e3f867b5Eric Anholt      if (type->is_matrix())
373c07290ddb2bf3095b9f5a1e0b33697999834fa0eEric Anholt	 subtype = type->column_type();
3743bdccbc3e0185fbca16eada2a76f55c6e3f867b5Eric Anholt      else
3753bdccbc3e0185fbca16eada2a76f55c6e3f867b5Eric Anholt	 subtype = type->fields.array;
37660177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt
37760177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt      entry->mem_ctx = ralloc_parent(entry->var);
37860177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt
37960177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt      entry->components = ralloc_array(mem_ctx,
38060177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt				       ir_variable *,
3813bdccbc3e0185fbca16eada2a76f55c6e3f867b5Eric Anholt				       entry->size);
38260177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt
3833bdccbc3e0185fbca16eada2a76f55c6e3f867b5Eric Anholt      for (unsigned int i = 0; i < entry->size; i++) {
38460177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt	 const char *name = ralloc_asprintf(mem_ctx, "%s_%d",
38560177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt					    entry->var->name, i);
38660177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt
38760177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt	 entry->components[i] =
3883bdccbc3e0185fbca16eada2a76f55c6e3f867b5Eric Anholt	    new(entry->mem_ctx) ir_variable(subtype, name, ir_var_temporary);
38960177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt	 entry->var->insert_before(entry->components[i]);
39060177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt      }
39160177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt
39260177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt      entry->var->remove();
39360177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt   }
39460177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt
39560177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt   ir_array_splitting_visitor split(&refs.variable_list);
39660177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt   visit_list_elements(&split, instructions);
39760177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt
39860177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt   if (debug)
39960177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt      _mesa_print_ir(instructions, NULL);
40060177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt
40160177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt   ralloc_free(mem_ctx);
40260177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt
40360177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt   return true;
40460177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt
40560177d5e2aec07ed6386a6935b118a356d58c4ecEric Anholt}
406