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_list(n
, &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 foreach_two_lists(formal_node
, &this->callee
->parameters
,
120 actual_node
, &this->actual_parameters
) {
121 ir_variable
*sig_param
= (ir_variable
*) formal_node
;
122 ir_rvalue
*param
= (ir_rvalue
*) actual_node
;
124 /* Generate a new variable for the parameter. */
125 if (sig_param
->type
->contains_opaque()) {
126 /* For opaque types, we want the inlined variable references
127 * referencing the passed in variable, since that will have
128 * the location information, which an assignment of an opaque
129 * variable wouldn't. Fix it up below.
131 parameters
[i
] = NULL
;
133 parameters
[i
] = sig_param
->clone(ctx
, ht
);
134 parameters
[i
]->data
.mode
= ir_var_auto
;
136 /* Remove the read-only decoration becuase we're going to write
137 * directly to this variable. If the cloned variable is left
138 * read-only and the inlined function is inside a loop, the loop
139 * analysis code will get confused.
141 parameters
[i
]->data
.read_only
= false;
142 next_ir
->insert_before(parameters
[i
]);
145 /* Move the actual param into our param variable if it's an 'in' type. */
146 if (parameters
[i
] && (sig_param
->data
.mode
== ir_var_function_in
||
147 sig_param
->data
.mode
== ir_var_const_in
||
148 sig_param
->data
.mode
== ir_var_function_inout
)) {
149 ir_assignment
*assign
;
151 assign
= new(ctx
) ir_assignment(new(ctx
) ir_dereference_variable(parameters
[i
]),
153 next_ir
->insert_before(assign
);
159 exec_list new_instructions
;
161 /* Generate the inlined body of the function to a new list */
162 foreach_list(n
, &callee
->body
) {
163 ir_instruction
*ir
= (ir_instruction
*) n
;
164 ir_instruction
*new_ir
= ir
->clone(ctx
, ht
);
166 new_instructions
.push_tail(new_ir
);
167 visit_tree(new_ir
, replace_return_with_assignment
, this->return_deref
);
170 /* If any opaque types were passed in, replace any deref of the
171 * opaque variable with a deref of the argument.
173 foreach_two_lists(formal_node
, &this->callee
->parameters
,
174 actual_node
, &this->actual_parameters
) {
175 ir_rvalue
*const param
= (ir_rvalue
*) actual_node
;
176 ir_variable
*sig_param
= (ir_variable
*) formal_node
;
178 if (sig_param
->type
->contains_opaque()) {
179 ir_dereference
*deref
= param
->as_dereference();
182 do_variable_replacement(&new_instructions
, sig_param
, deref
);
186 /* Now push those new instructions in. */
187 next_ir
->insert_before(&new_instructions
);
189 /* Copy back the value of any 'out' parameters from the function body
190 * variables to our own.
193 foreach_two_lists(formal_node
, &this->callee
->parameters
,
194 actual_node
, &this->actual_parameters
) {
195 ir_rvalue
*const param
= (ir_rvalue
*) actual_node
;
196 const ir_variable
*const sig_param
= (ir_variable
*) formal_node
;
198 /* Move our param variable into the actual param if it's an 'out' type. */
199 if (parameters
[i
] && (sig_param
->data
.mode
== ir_var_function_out
||
200 sig_param
->data
.mode
== ir_var_function_inout
)) {
201 ir_assignment
*assign
;
203 assign
= new(ctx
) ir_assignment(param
->clone(ctx
, NULL
)->as_rvalue(),
204 new(ctx
) ir_dereference_variable(parameters
[i
]),
206 next_ir
->insert_before(assign
);
212 delete [] parameters
;
219 ir_function_inlining_visitor::visit_enter(ir_expression
*ir
)
222 return visit_continue_with_parent
;
227 ir_function_inlining_visitor::visit_enter(ir_return
*ir
)
230 return visit_continue_with_parent
;
235 ir_function_inlining_visitor::visit_enter(ir_texture
*ir
)
238 return visit_continue_with_parent
;
243 ir_function_inlining_visitor::visit_enter(ir_swizzle
*ir
)
246 return visit_continue_with_parent
;
251 ir_function_inlining_visitor::visit_enter(ir_call
*ir
)
253 if (can_inline(ir
)) {
254 ir
->generate_inline(ir
);
256 this->progress
= true;
259 return visit_continue
;
264 * Replaces references to the "orig" variable with a clone of "repl."
266 * From the spec, opaque types can appear in the tree as function
267 * (non-out) parameters and as the result of array indexing and
268 * structure field selection. In our builtin implementation, they
269 * also appear in the sampler field of an ir_tex instruction.
272 class ir_variable_replacement_visitor
: public ir_hierarchical_visitor
{
274 ir_variable_replacement_visitor(ir_variable
*orig
, ir_dereference
*repl
)
280 virtual ~ir_variable_replacement_visitor()
284 virtual ir_visitor_status
visit_leave(ir_call
*);
285 virtual ir_visitor_status
visit_leave(ir_dereference_array
*);
286 virtual ir_visitor_status
visit_leave(ir_dereference_record
*);
287 virtual ir_visitor_status
visit_leave(ir_texture
*);
289 void replace_deref(ir_dereference
**deref
);
290 void replace_rvalue(ir_rvalue
**rvalue
);
293 ir_dereference
*repl
;
297 ir_variable_replacement_visitor::replace_deref(ir_dereference
**deref
)
299 ir_dereference_variable
*deref_var
= (*deref
)->as_dereference_variable();
300 if (deref_var
&& deref_var
->var
== this->orig
) {
301 *deref
= this->repl
->clone(ralloc_parent(*deref
), NULL
);
306 ir_variable_replacement_visitor::replace_rvalue(ir_rvalue
**rvalue
)
311 ir_dereference
*deref
= (*rvalue
)->as_dereference();
316 replace_deref(&deref
);
321 ir_variable_replacement_visitor::visit_leave(ir_texture
*ir
)
323 replace_deref(&ir
->sampler
);
325 return visit_continue
;
329 ir_variable_replacement_visitor::visit_leave(ir_dereference_array
*ir
)
331 replace_rvalue(&ir
->array
);
332 return visit_continue
;
336 ir_variable_replacement_visitor::visit_leave(ir_dereference_record
*ir
)
338 replace_rvalue(&ir
->record
);
339 return visit_continue
;
343 ir_variable_replacement_visitor::visit_leave(ir_call
*ir
)
345 foreach_list_safe(n
, &ir
->actual_parameters
) {
346 ir_rvalue
*param
= (ir_rvalue
*) n
;
347 ir_rvalue
*new_param
= param
;
348 replace_rvalue(&new_param
);
350 if (new_param
!= param
) {
351 param
->replace_with(new_param
);
354 return visit_continue
;
358 do_variable_replacement(exec_list
*instructions
,
360 ir_dereference
*repl
)
362 ir_variable_replacement_visitor
v(orig
, repl
);
364 visit_list_elements(&v
, instructions
);