Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

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