2 * Copyright © 2010 Intel Corporation
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:
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
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.
25 * \file opt_function_inlining.cpp
27 * Replaces calls to functions with the body of the function.
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"
38 do_variable_replacement(exec_list
*instructions
,
40 ir_dereference
*repl
);
44 class ir_function_inlining_visitor
: public ir_hierarchical_visitor
{
46 ir_function_inlining_visitor()
51 virtual ~ir_function_inlining_visitor()
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
*);
65 } /* unnamed namespace */
68 do_function_inlining(exec_list
*instructions
)
70 ir_function_inlining_visitor v
;
78 replace_return_with_assignment(ir_instruction
*ir
, void *data
)
80 void *ctx
= ralloc_parent(ir
);
81 ir_dereference
*orig_deref
= (ir_dereference
*) data
;
82 ir_return
*ret
= ir
->as_return();
86 ir_rvalue
*lhs
= orig_deref
->clone(ctx
, NULL
);
87 ret
->replace_with(new(ctx
) ir_assignment(lhs
, ret
->value
, NULL
));
89 /* un-valued return has to be the last return, or we shouldn't
90 * have reached here. (see can_inline()).
92 assert(ret
->next
->is_tail_sentinel());
99 ir_call::generate_inline(ir_instruction
*next_ir
)
101 void *ctx
= ralloc_parent(this);
102 ir_variable
**parameters
;
105 struct hash_table
*ht
;
107 ht
= hash_table_ctor(0, hash_table_pointer_hash
, hash_table_pointer_compare
);
110 foreach_iter(exec_list_iterator
, iter_sig
, this->callee
->parameters
)
113 parameters
= new ir_variable
*[num_parameters
];
115 /* Generate the declarations for the parameters to our inlined code,
116 * and set up the mapping of real function body variables to ours.
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();
125 /* Generate a new variable for the parameter. */
126 if (sig_param
->type
->contains_opaque()) {
127 /* For opaque types, we want the inlined variable references
128 * referencing the passed in variable, since that will have
129 * the location information, which an assignment of an opaque
130 * variable wouldn't. Fix it up below.
132 parameters
[i
] = NULL
;
134 parameters
[i
] = sig_param
->clone(ctx
, ht
);
135 parameters
[i
]->data
.mode
= ir_var_auto
;
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.
142 parameters
[i
]->data
.read_only
= false;
143 next_ir
->insert_before(parameters
[i
]);
146 /* Move the actual param into our param variable if it's an 'in' type. */
147 if (parameters
[i
] && (sig_param
->data
.mode
== ir_var_function_in
||
148 sig_param
->data
.mode
== ir_var_const_in
||
149 sig_param
->data
.mode
== ir_var_function_inout
)) {
150 ir_assignment
*assign
;
152 assign
= new(ctx
) ir_assignment(new(ctx
) ir_dereference_variable(parameters
[i
]),
154 next_ir
->insert_before(assign
);
157 sig_param_iter
.next();
161 exec_list new_instructions
;
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
);
168 new_instructions
.push_tail(new_ir
);
169 visit_tree(new_ir
, replace_return_with_assignment
, this->return_deref
);
172 /* If any opaque types were passed in, replace any deref of the
173 * opaque variable with a deref of the argument.
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();
181 if (sig_param
->type
->contains_opaque()) {
182 ir_dereference
*deref
= param
->as_dereference();
185 do_variable_replacement(&new_instructions
, sig_param
, deref
);
188 sig_param_iter
.next();
191 /* Now push those new instructions in. */
192 next_ir
->insert_before(&new_instructions
);
194 /* Copy back the value of any 'out' parameters from the function body
195 * variables to our own.
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();
204 /* Move our param variable into the actual param if it's an 'out' type. */
205 if (parameters
[i
] && (sig_param
->data
.mode
== ir_var_function_out
||
206 sig_param
->data
.mode
== ir_var_function_inout
)) {
207 ir_assignment
*assign
;
209 assign
= new(ctx
) ir_assignment(param
->clone(ctx
, NULL
)->as_rvalue(),
210 new(ctx
) ir_dereference_variable(parameters
[i
]),
212 next_ir
->insert_before(assign
);
216 sig_param_iter
.next();
219 delete [] parameters
;
226 ir_function_inlining_visitor::visit_enter(ir_expression
*ir
)
229 return visit_continue_with_parent
;
234 ir_function_inlining_visitor::visit_enter(ir_return
*ir
)
237 return visit_continue_with_parent
;
242 ir_function_inlining_visitor::visit_enter(ir_texture
*ir
)
245 return visit_continue_with_parent
;
250 ir_function_inlining_visitor::visit_enter(ir_swizzle
*ir
)
253 return visit_continue_with_parent
;
258 ir_function_inlining_visitor::visit_enter(ir_call
*ir
)
260 if (can_inline(ir
)) {
261 ir
->generate_inline(ir
);
263 this->progress
= true;
266 return visit_continue
;
271 * Replaces references to the "orig" variable with a clone of "repl."
273 * From the spec, opaque types 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.
279 class ir_variable_replacement_visitor
: public ir_hierarchical_visitor
{
281 ir_variable_replacement_visitor(ir_variable
*orig
, ir_dereference
*repl
)
287 virtual ~ir_variable_replacement_visitor()
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
*);
296 void replace_deref(ir_dereference
**deref
);
297 void replace_rvalue(ir_rvalue
**rvalue
);
300 ir_dereference
*repl
;
304 ir_variable_replacement_visitor::replace_deref(ir_dereference
**deref
)
306 ir_dereference_variable
*deref_var
= (*deref
)->as_dereference_variable();
307 if (deref_var
&& deref_var
->var
== this->orig
) {
308 *deref
= this->repl
->clone(ralloc_parent(*deref
), NULL
);
313 ir_variable_replacement_visitor::replace_rvalue(ir_rvalue
**rvalue
)
318 ir_dereference
*deref
= (*rvalue
)->as_dereference();
323 replace_deref(&deref
);
328 ir_variable_replacement_visitor::visit_leave(ir_texture
*ir
)
330 replace_deref(&ir
->sampler
);
332 return visit_continue
;
336 ir_variable_replacement_visitor::visit_leave(ir_dereference_array
*ir
)
338 replace_rvalue(&ir
->array
);
339 return visit_continue
;
343 ir_variable_replacement_visitor::visit_leave(ir_dereference_record
*ir
)
345 replace_rvalue(&ir
->record
);
346 return visit_continue
;
350 ir_variable_replacement_visitor::visit_leave(ir_call
*ir
)
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
);
357 if (new_param
!= param
) {
358 param
->replace_with(new_param
);
361 return visit_continue
;
365 do_variable_replacement(exec_list
*instructions
,
367 ir_dereference
*repl
)
369 ir_variable_replacement_visitor
v(orig
, repl
);
371 visit_list_elements(&v
, instructions
);