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
;
103 unsigned num_parameters
;
105 struct hash_table
*ht
;
107 ht
= hash_table_ctor(0, hash_table_pointer_hash
, hash_table_pointer_compare
);
109 num_parameters
= this->callee
->parameters
.length();
110 parameters
= new ir_variable
*[num_parameters
];
112 /* Generate the declarations for the parameters to our inlined code,
113 * and set up the mapping of real function body variables to ours.
116 foreach_two_lists(formal_node
, &this->callee
->parameters
,
117 actual_node
, &this->actual_parameters
) {
118 ir_variable
*sig_param
= (ir_variable
*) formal_node
;
119 ir_rvalue
*param
= (ir_rvalue
*) actual_node
;
121 /* Generate a new variable for the parameter. */
122 if (sig_param
->type
->contains_opaque()) {
123 /* For opaque types, we want the inlined variable references
124 * referencing the passed in variable, since that will have
125 * the location information, which an assignment of an opaque
126 * variable wouldn't. Fix it up below.
128 parameters
[i
] = NULL
;
130 parameters
[i
] = sig_param
->clone(ctx
, ht
);
131 parameters
[i
]->data
.mode
= ir_var_auto
;
133 /* Remove the read-only decoration becuase we're going to write
134 * directly to this variable. If the cloned variable is left
135 * read-only and the inlined function is inside a loop, the loop
136 * analysis code will get confused.
138 parameters
[i
]->data
.read_only
= false;
139 next_ir
->insert_before(parameters
[i
]);
142 /* Move the actual param into our param variable if it's an 'in' type. */
143 if (parameters
[i
] && (sig_param
->data
.mode
== ir_var_function_in
||
144 sig_param
->data
.mode
== ir_var_const_in
||
145 sig_param
->data
.mode
== ir_var_function_inout
)) {
146 ir_assignment
*assign
;
148 assign
= new(ctx
) ir_assignment(new(ctx
) ir_dereference_variable(parameters
[i
]),
150 next_ir
->insert_before(assign
);
156 exec_list new_instructions
;
158 /* Generate the inlined body of the function to a new list */
159 foreach_in_list(ir_instruction
, ir
, &callee
->body
) {
160 ir_instruction
*new_ir
= ir
->clone(ctx
, ht
);
162 new_instructions
.push_tail(new_ir
);
163 visit_tree(new_ir
, replace_return_with_assignment
, this->return_deref
);
166 /* If any opaque types were passed in, replace any deref of the
167 * opaque variable with a deref of the argument.
169 foreach_two_lists(formal_node
, &this->callee
->parameters
,
170 actual_node
, &this->actual_parameters
) {
171 ir_rvalue
*const param
= (ir_rvalue
*) actual_node
;
172 ir_variable
*sig_param
= (ir_variable
*) formal_node
;
174 if (sig_param
->type
->contains_opaque()) {
175 ir_dereference
*deref
= param
->as_dereference();
178 do_variable_replacement(&new_instructions
, sig_param
, deref
);
182 /* Now push those new instructions in. */
183 next_ir
->insert_before(&new_instructions
);
185 /* Copy back the value of any 'out' parameters from the function body
186 * variables to our own.
189 foreach_two_lists(formal_node
, &this->callee
->parameters
,
190 actual_node
, &this->actual_parameters
) {
191 ir_rvalue
*const param
= (ir_rvalue
*) actual_node
;
192 const ir_variable
*const sig_param
= (ir_variable
*) formal_node
;
194 /* Move our param variable into the actual param if it's an 'out' type. */
195 if (parameters
[i
] && (sig_param
->data
.mode
== ir_var_function_out
||
196 sig_param
->data
.mode
== ir_var_function_inout
)) {
197 ir_assignment
*assign
;
199 assign
= new(ctx
) ir_assignment(param
->clone(ctx
, NULL
)->as_rvalue(),
200 new(ctx
) ir_dereference_variable(parameters
[i
]),
202 next_ir
->insert_before(assign
);
208 delete [] parameters
;
215 ir_function_inlining_visitor::visit_enter(ir_expression
*ir
)
218 return visit_continue_with_parent
;
223 ir_function_inlining_visitor::visit_enter(ir_return
*ir
)
226 return visit_continue_with_parent
;
231 ir_function_inlining_visitor::visit_enter(ir_texture
*ir
)
234 return visit_continue_with_parent
;
239 ir_function_inlining_visitor::visit_enter(ir_swizzle
*ir
)
242 return visit_continue_with_parent
;
247 ir_function_inlining_visitor::visit_enter(ir_call
*ir
)
249 if (can_inline(ir
)) {
250 ir
->generate_inline(ir
);
252 this->progress
= true;
255 return visit_continue
;
260 * Replaces references to the "orig" variable with a clone of "repl."
262 * From the spec, opaque types can appear in the tree as function
263 * (non-out) parameters and as the result of array indexing and
264 * structure field selection. In our builtin implementation, they
265 * also appear in the sampler field of an ir_tex instruction.
268 class ir_variable_replacement_visitor
: public ir_hierarchical_visitor
{
270 ir_variable_replacement_visitor(ir_variable
*orig
, ir_dereference
*repl
)
276 virtual ~ir_variable_replacement_visitor()
280 virtual ir_visitor_status
visit_leave(ir_call
*);
281 virtual ir_visitor_status
visit_leave(ir_dereference_array
*);
282 virtual ir_visitor_status
visit_leave(ir_dereference_record
*);
283 virtual ir_visitor_status
visit_leave(ir_texture
*);
285 void replace_deref(ir_dereference
**deref
);
286 void replace_rvalue(ir_rvalue
**rvalue
);
289 ir_dereference
*repl
;
293 ir_variable_replacement_visitor::replace_deref(ir_dereference
**deref
)
295 ir_dereference_variable
*deref_var
= (*deref
)->as_dereference_variable();
296 if (deref_var
&& deref_var
->var
== this->orig
) {
297 *deref
= this->repl
->clone(ralloc_parent(*deref
), NULL
);
302 ir_variable_replacement_visitor::replace_rvalue(ir_rvalue
**rvalue
)
307 ir_dereference
*deref
= (*rvalue
)->as_dereference();
312 replace_deref(&deref
);
317 ir_variable_replacement_visitor::visit_leave(ir_texture
*ir
)
319 replace_deref(&ir
->sampler
);
321 return visit_continue
;
325 ir_variable_replacement_visitor::visit_leave(ir_dereference_array
*ir
)
327 replace_rvalue(&ir
->array
);
328 return visit_continue
;
332 ir_variable_replacement_visitor::visit_leave(ir_dereference_record
*ir
)
334 replace_rvalue(&ir
->record
);
335 return visit_continue
;
339 ir_variable_replacement_visitor::visit_leave(ir_call
*ir
)
341 foreach_in_list_safe(ir_rvalue
, param
, &ir
->actual_parameters
) {
342 ir_rvalue
*new_param
= param
;
343 replace_rvalue(&new_param
);
345 if (new_param
!= param
) {
346 param
->replace_with(new_param
);
349 return visit_continue
;
353 do_variable_replacement(exec_list
*instructions
,
355 ir_dereference
*repl
)
357 ir_variable_replacement_visitor
v(orig
, repl
);
359 visit_list_elements(&v
, instructions
);