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