Subversion Repositories Kolibri OS

Rev

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_function_inlining.cpp
26
 *
27
 * Replaces calls to functions with the body of the function.
28
 */
29
 
30
#include "ir.h"
31
#include "ir_visitor.h"
32
#include "ir_function_inlining.h"
33
#include "ir_expression_flattening.h"
34
#include "glsl_types.h"
35
#include "program/hash_table.h"
36
 
37
static void
38
do_sampler_replacement(exec_list *instructions,
39
		       ir_variable *sampler,
40
		       ir_dereference *deref);
41
 
42
namespace {
43
 
44
class ir_function_inlining_visitor : public ir_hierarchical_visitor {
45
public:
46
   ir_function_inlining_visitor()
47
   {
48
      progress = false;
49
   }
50
 
51
   virtual ~ir_function_inlining_visitor()
52
   {
53
      /* empty */
54
   }
55
 
56
   virtual ir_visitor_status visit_enter(ir_expression *);
57
   virtual ir_visitor_status visit_enter(ir_call *);
58
   virtual ir_visitor_status visit_enter(ir_return *);
59
   virtual ir_visitor_status visit_enter(ir_texture *);
60
   virtual ir_visitor_status visit_enter(ir_swizzle *);
61
 
62
   bool progress;
63
};
64
 
65
} /* unnamed namespace */
66
 
67
bool
68
do_function_inlining(exec_list *instructions)
69
{
70
   ir_function_inlining_visitor v;
71
 
72
   v.run(instructions);
73
 
74
   return v.progress;
75
}
76
 
77
static void
78
replace_return_with_assignment(ir_instruction *ir, void *data)
79
{
80
   void *ctx = ralloc_parent(ir);
81
   ir_dereference *orig_deref = (ir_dereference *) data;
82
   ir_return *ret = ir->as_return();
83
 
84
   if (ret) {
85
      if (ret->value) {
86
	 ir_rvalue *lhs = orig_deref->clone(ctx, NULL);
87
	 ret->replace_with(new(ctx) ir_assignment(lhs, ret->value, NULL));
88
      } else {
89
	 /* un-valued return has to be the last return, or we shouldn't
90
	  * have reached here. (see can_inline()).
91
	  */
92
	 assert(ret->next->is_tail_sentinel());
93
	 ret->remove();
94
      }
95
   }
96
}
97
 
98
void
99
ir_call::generate_inline(ir_instruction *next_ir)
100
{
101
   void *ctx = ralloc_parent(this);
102
   ir_variable **parameters;
103
   int num_parameters;
104
   int i;
105
   struct hash_table *ht;
106
 
107
   ht = hash_table_ctor(0, hash_table_pointer_hash, hash_table_pointer_compare);
108
 
109
   num_parameters = 0;
110
   foreach_iter(exec_list_iterator, iter_sig, this->callee->parameters)
111
      num_parameters++;
112
 
113
   parameters = new ir_variable *[num_parameters];
114
 
115
   /* Generate the declarations for the parameters to our inlined code,
116
    * and set up the mapping of real function body variables to ours.
117
    */
118
   i = 0;
119
   exec_list_iterator sig_param_iter = this->callee->parameters.iterator();
120
   exec_list_iterator param_iter = this->actual_parameters.iterator();
121
   for (i = 0; i < num_parameters; i++) {
122
      ir_variable *sig_param = (ir_variable *) sig_param_iter.get();
123
      ir_rvalue *param = (ir_rvalue *) param_iter.get();
124
 
125
      /* Generate a new variable for the parameter. */
126
      if (sig_param->type->base_type == GLSL_TYPE_SAMPLER) {
127
	 /* For samplers, we want the inlined sampler references
128
	  * referencing the passed in sampler variable, since that
129
	  * will have the location information, which an assignment of
130
	  * a sampler wouldn't.  Fix it up below.
131
	  */
132
	 parameters[i] = NULL;
133
      } else {
134
	 parameters[i] = sig_param->clone(ctx, ht);
135
	 parameters[i]->mode = ir_var_auto;
136
 
137
	 /* Remove the read-only decoration becuase we're going to write
138
	  * directly to this variable.  If the cloned variable is left
139
	  * read-only and the inlined function is inside a loop, the loop
140
	  * analysis code will get confused.
141
	  */
142
	 parameters[i]->read_only = false;
143
	 next_ir->insert_before(parameters[i]);
144
      }
145
 
146
      /* Move the actual param into our param variable if it's an 'in' type. */
147
      if (parameters[i] && (sig_param->mode == ir_var_function_in ||
148
			    sig_param->mode == ir_var_const_in ||
149
			    sig_param->mode == ir_var_function_inout)) {
150
	 ir_assignment *assign;
151
 
152
	 assign = new(ctx) ir_assignment(new(ctx) ir_dereference_variable(parameters[i]),
153
					 param, NULL);
154
	 next_ir->insert_before(assign);
155
      }
156
 
157
      sig_param_iter.next();
158
      param_iter.next();
159
   }
160
 
161
   exec_list new_instructions;
162
 
163
   /* Generate the inlined body of the function to a new list */
164
   foreach_iter(exec_list_iterator, iter, callee->body) {
165
      ir_instruction *ir = (ir_instruction *)iter.get();
166
      ir_instruction *new_ir = ir->clone(ctx, ht);
167
 
168
      new_instructions.push_tail(new_ir);
169
      visit_tree(new_ir, replace_return_with_assignment, this->return_deref);
170
   }
171
 
172
   /* If any samplers were passed in, replace any deref of the sampler
173
    * with a deref of the sampler argument.
174
    */
175
   param_iter = this->actual_parameters.iterator();
176
   sig_param_iter = this->callee->parameters.iterator();
177
   for (i = 0; i < num_parameters; i++) {
178
      ir_instruction *const param = (ir_instruction *) param_iter.get();
179
      ir_variable *sig_param = (ir_variable *) sig_param_iter.get();
180
 
181
      if (sig_param->type->base_type == GLSL_TYPE_SAMPLER) {
182
	 ir_dereference *deref = param->as_dereference();
183
 
184
	 assert(deref);
185
	 do_sampler_replacement(&new_instructions, sig_param, deref);
186
      }
187
      param_iter.next();
188
      sig_param_iter.next();
189
   }
190
 
191
   /* Now push those new instructions in. */
192
   next_ir->insert_before(&new_instructions);
193
 
194
   /* Copy back the value of any 'out' parameters from the function body
195
    * variables to our own.
196
    */
197
   i = 0;
198
   param_iter = this->actual_parameters.iterator();
199
   sig_param_iter = this->callee->parameters.iterator();
200
   for (i = 0; i < num_parameters; i++) {
201
      ir_instruction *const param = (ir_instruction *) param_iter.get();
202
      const ir_variable *const sig_param = (ir_variable *) sig_param_iter.get();
203
 
204
      /* Move our param variable into the actual param if it's an 'out' type. */
205
      if (parameters[i] && (sig_param->mode == ir_var_function_out ||
206
			    sig_param->mode == ir_var_function_inout)) {
207
	 ir_assignment *assign;
208
 
209
	 assign = new(ctx) ir_assignment(param->clone(ctx, NULL)->as_rvalue(),
210
					 new(ctx) ir_dereference_variable(parameters[i]),
211
					 NULL);
212
	 next_ir->insert_before(assign);
213
      }
214
 
215
      param_iter.next();
216
      sig_param_iter.next();
217
   }
218
 
219
   delete [] parameters;
220
 
221
   hash_table_dtor(ht);
222
}
223
 
224
 
225
ir_visitor_status
226
ir_function_inlining_visitor::visit_enter(ir_expression *ir)
227
{
228
   (void) ir;
229
   return visit_continue_with_parent;
230
}
231
 
232
 
233
ir_visitor_status
234
ir_function_inlining_visitor::visit_enter(ir_return *ir)
235
{
236
   (void) ir;
237
   return visit_continue_with_parent;
238
}
239
 
240
 
241
ir_visitor_status
242
ir_function_inlining_visitor::visit_enter(ir_texture *ir)
243
{
244
   (void) ir;
245
   return visit_continue_with_parent;
246
}
247
 
248
 
249
ir_visitor_status
250
ir_function_inlining_visitor::visit_enter(ir_swizzle *ir)
251
{
252
   (void) ir;
253
   return visit_continue_with_parent;
254
}
255
 
256
 
257
ir_visitor_status
258
ir_function_inlining_visitor::visit_enter(ir_call *ir)
259
{
260
   if (can_inline(ir)) {
261
      ir->generate_inline(ir);
262
      ir->remove();
263
      this->progress = true;
264
   }
265
 
266
   return visit_continue;
267
}
268
 
269
 
270
/**
271
 * Replaces references to the "sampler" variable with a clone of "deref."
272
 *
273
 * From the spec, samplers can appear in the tree as function
274
 * (non-out) parameters and as the result of array indexing and
275
 * structure field selection.  In our builtin implementation, they
276
 * also appear in the sampler field of an ir_tex instruction.
277
 */
278
 
279
class ir_sampler_replacement_visitor : public ir_hierarchical_visitor {
280
public:
281
   ir_sampler_replacement_visitor(ir_variable *sampler, ir_dereference *deref)
282
   {
283
      this->sampler = sampler;
284
      this->deref = deref;
285
   }
286
 
287
   virtual ~ir_sampler_replacement_visitor()
288
   {
289
   }
290
 
291
   virtual ir_visitor_status visit_leave(ir_call *);
292
   virtual ir_visitor_status visit_leave(ir_dereference_array *);
293
   virtual ir_visitor_status visit_leave(ir_dereference_record *);
294
   virtual ir_visitor_status visit_leave(ir_texture *);
295
 
296
   void replace_deref(ir_dereference **deref);
297
   void replace_rvalue(ir_rvalue **rvalue);
298
 
299
   ir_variable *sampler;
300
   ir_dereference *deref;
301
};
302
 
303
void
304
ir_sampler_replacement_visitor::replace_deref(ir_dereference **deref)
305
{
306
   ir_dereference_variable *deref_var = (*deref)->as_dereference_variable();
307
   if (deref_var && deref_var->var == this->sampler) {
308
      *deref = this->deref->clone(ralloc_parent(*deref), NULL);
309
   }
310
}
311
 
312
void
313
ir_sampler_replacement_visitor::replace_rvalue(ir_rvalue **rvalue)
314
{
315
   if (!*rvalue)
316
      return;
317
 
318
   ir_dereference *deref = (*rvalue)->as_dereference();
319
 
320
   if (!deref)
321
      return;
322
 
323
   replace_deref(&deref);
324
   *rvalue = deref;
325
}
326
 
327
ir_visitor_status
328
ir_sampler_replacement_visitor::visit_leave(ir_texture *ir)
329
{
330
   replace_deref(&ir->sampler);
331
 
332
   return visit_continue;
333
}
334
 
335
ir_visitor_status
336
ir_sampler_replacement_visitor::visit_leave(ir_dereference_array *ir)
337
{
338
   replace_rvalue(&ir->array);
339
   return visit_continue;
340
}
341
 
342
ir_visitor_status
343
ir_sampler_replacement_visitor::visit_leave(ir_dereference_record *ir)
344
{
345
   replace_rvalue(&ir->record);
346
   return visit_continue;
347
}
348
 
349
ir_visitor_status
350
ir_sampler_replacement_visitor::visit_leave(ir_call *ir)
351
{
352
   foreach_iter(exec_list_iterator, iter, *ir) {
353
      ir_rvalue *param = (ir_rvalue *)iter.get();
354
      ir_rvalue *new_param = param;
355
      replace_rvalue(&new_param);
356
 
357
      if (new_param != param) {
358
	 param->replace_with(new_param);
359
      }
360
   }
361
   return visit_continue;
362
}
363
 
364
static void
365
do_sampler_replacement(exec_list *instructions,
366
		       ir_variable *sampler,
367
		       ir_dereference *deref)
368
{
369
   ir_sampler_replacement_visitor v(sampler, deref);
370
 
371
   visit_list_elements(&v, instructions);
372
}