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 ir_function_inlining.cpp
27 * Replaces calls to functions with the body of the function.
32 #include "ir_visitor.h"
33 #include "ir_function_inlining.h"
34 #include "ir_expression_flattening.h"
35 #include "glsl_types.h"
37 class variable_remap
: public exec_node
{
39 variable_remap(const ir_variable
*old_var
, ir_variable
*new_var
)
40 : old_var(old_var
), new_var(new_var
)
44 const ir_variable
*old_var
;
48 class ir_function_cloning_visitor
: public ir_visitor
{
50 ir_function_cloning_visitor(ir_variable
*retval
)
56 virtual ~ir_function_cloning_visitor()
61 void remap_variable(const ir_variable
*old_var
, ir_variable
*new_var
) {
62 variable_remap
*remap
= new variable_remap(old_var
, new_var
);
63 this->remap_list
.push_tail(remap
);
66 ir_variable
*get_remapped_variable(ir_variable
*var
) {
67 foreach_iter(exec_list_iterator
, iter
, this->remap_list
) {
68 variable_remap
*remap
= (variable_remap
*)iter
.get();
70 if (var
== remap
->old_var
)
71 return remap
->new_var
;
74 /* Not a reapped variable, so a global scoped reference, for example. */
78 /* List of variable_remap for mapping from original function body variables
79 * to inlined function body variables.
83 /* Return value for the inlined function. */
89 * As typical for the visitor pattern, there must be one \c visit method for
90 * each concrete subclass of \c ir_instruction. Virtual base classes within
91 * the hierarchy should not have \c visit methods.
94 virtual void visit(ir_variable
*);
95 virtual void visit(ir_loop
*);
96 virtual void visit(ir_loop_jump
*);
97 virtual void visit(ir_function_signature
*);
98 virtual void visit(ir_function
*);
99 virtual void visit(ir_expression
*);
100 virtual void visit(ir_swizzle
*);
101 virtual void visit(ir_dereference
*);
102 virtual void visit(ir_assignment
*);
103 virtual void visit(ir_constant
*);
104 virtual void visit(ir_call
*);
105 virtual void visit(ir_return
*);
106 virtual void visit(ir_if
*);
109 ir_instruction
*result
;
113 ir_function_cloning_visitor::visit(ir_variable
*ir
)
115 ir_variable
*new_var
= ir
->clone();
117 this->result
= new_var
;
119 this->remap_variable(ir
, new_var
);
123 ir_function_cloning_visitor::visit(ir_loop
*ir
)
130 ir_function_cloning_visitor::visit(ir_loop_jump
*ir
)
138 ir_function_cloning_visitor::visit(ir_function_signature
*ir
)
146 ir_function_cloning_visitor::visit(ir_function
*ir
)
153 ir_function_cloning_visitor::visit(ir_expression
*ir
)
155 unsigned int operand
;
156 ir_rvalue
*op
[2] = {NULL
, NULL
};
158 for (operand
= 0; operand
< ir
->get_num_operands(); operand
++) {
159 ir
->operands
[operand
]->accept(this);
160 op
[operand
] = this->result
->as_rvalue();
164 this->result
= new ir_expression(ir
->operation
, ir
->type
, op
[0], op
[1]);
169 ir_function_cloning_visitor::visit(ir_swizzle
*ir
)
171 ir
->val
->accept(this);
173 this->result
= new ir_swizzle(this->result
->as_rvalue(), ir
->mask
);
177 ir_function_cloning_visitor::visit(ir_dereference
*ir
)
179 if (ir
->mode
== ir_dereference::ir_reference_variable
) {
180 ir_variable
*old_var
= ir
->var
->as_variable();
182 /* If it's a deref of a real variable, then we need to remap it if
183 * it was local to the function.
186 ir_variable
*new_var
;
188 new_var
= this->get_remapped_variable(old_var
);
190 this->result
= new ir_dereference(new_var
);
192 ir
->var
->accept(this);
194 this->result
= new ir_dereference(this->result
);
196 } else if (ir
->mode
== ir_dereference::ir_reference_array
) {
197 ir_instruction
*variable
;
200 ir
->var
->accept(this);
201 variable
= this->result
;
203 ir
->selector
.array_index
->accept(this);
204 index
= this->result
->as_rvalue();
206 this->result
= new ir_dereference(variable
, index
);
208 assert(ir
->mode
== ir_dereference::ir_reference_record
);
209 /* FINISHME: inlining of structure references */
215 ir_function_cloning_visitor::visit(ir_assignment
*ir
)
217 ir_rvalue
*lhs
, *rhs
, *condition
= NULL
;
219 ir
->lhs
->accept(this);
220 lhs
= this->result
->as_rvalue();
222 ir
->rhs
->accept(this);
223 rhs
= this->result
->as_rvalue();
226 ir
->condition
->accept(this);
227 condition
= this->result
->as_rvalue();
230 this->result
= new ir_assignment(lhs
, rhs
, condition
);
235 ir_function_cloning_visitor::visit(ir_constant
*ir
)
237 this->result
= ir
->clone();
242 ir_function_cloning_visitor::visit(ir_call
*ir
)
244 exec_list parameters
;
246 foreach_iter(exec_list_iterator
, iter
, *ir
) {
247 ir_rvalue
*param
= (ir_rvalue
*)iter
.get();
250 parameters
.push_tail(this->result
);
253 this->result
= new ir_call(ir
->get_callee(), ¶meters
);
258 ir_function_cloning_visitor::visit(ir_return
*ir
)
262 assert(this->retval
);
264 rval
= ir
->get_value();
266 rval
= this->result
->as_rvalue();
269 result
= new ir_assignment(new ir_dereference(this->retval
),
270 ir
->get_value(), NULL
);
275 ir_function_cloning_visitor::visit(ir_if
*ir
)
282 can_inline(ir_call
*call
)
284 bool found_return
= false;
286 /* FINISHME: Right now we only allow a single statement that is a return.
288 foreach_iter(exec_list_iterator
, iter
, call
->get_callee()->body
) {
289 ir_instruction
*ir
= (ir_instruction
*)iter
.get();
290 if (ir
->get_next()->get_next() != NULL
)
293 if (!ir
->as_return())
303 automatic_inlining_predicate(ir_instruction
*ir
)
305 ir_call
*call
= ir
->as_call();
307 if (call
&& can_inline(call
))
314 do_function_inlining(exec_list
*instructions
)
316 bool progress
= false;
318 do_expression_flattening(instructions
, automatic_inlining_predicate
);
320 foreach_iter(exec_list_iterator
, iter
, *instructions
) {
321 ir_instruction
*ir
= (ir_instruction
*)iter
.get();
322 ir_assignment
*assign
= ir
->as_assignment();
326 call
= assign
->rhs
->as_call();
327 if (!call
|| !can_inline(call
))
330 /* generates the parameter setup, function body, and returns the return
331 * value of the function
333 ir_rvalue
*rhs
= call
->generate_inline(ir
);
338 } else if ((call
= ir
->as_call()) && can_inline(call
)) {
339 (void)call
->generate_inline(ir
);
343 ir_function_inlining_visitor v
;
352 ir_call::generate_inline(ir_instruction
*next_ir
)
354 ir_variable
**parameters
;
357 ir_variable
*retval
= NULL
;
360 foreach_iter(exec_list_iterator
, iter_sig
, this->callee
->parameters
)
363 parameters
= new ir_variable
*[num_parameters
];
365 /* Generate storage for the return value. */
366 if (this->callee
->return_type
) {
367 retval
= new ir_variable(this->callee
->return_type
, "__retval");
368 next_ir
->insert_before(retval
);
371 ir_function_cloning_visitor v
= ir_function_cloning_visitor(retval
);
373 /* Generate the declarations for the parameters to our inlined code,
374 * and set up the mapping of real function body variables to ours.
377 exec_list_iterator sig_param_iter
= this->callee
->parameters
.iterator();
378 exec_list_iterator param_iter
= this->actual_parameters
.iterator();
379 for (i
= 0; i
< num_parameters
; i
++) {
380 const ir_variable
*const sig_param
= (ir_variable
*) sig_param_iter
.get();
381 ir_rvalue
*param
= (ir_rvalue
*) param_iter
.get();
383 /* Generate a new variable for the parameter. */
384 parameters
[i
] = sig_param
->clone();
385 next_ir
->insert_before(parameters
[i
]);
387 v
.remap_variable(sig_param
, parameters
[i
]);
389 /* Move the actual param into our param variable if it's an 'in' type. */
390 if (parameters
[i
]->mode
== ir_var_in
||
391 parameters
[i
]->mode
== ir_var_inout
) {
392 ir_assignment
*assign
;
394 assign
= new ir_assignment(new ir_dereference(parameters
[i
]),
396 next_ir
->insert_before(assign
);
399 sig_param_iter
.next();
403 /* Generate the inlined body of the function. */
404 foreach_iter(exec_list_iterator
, iter
, callee
->body
) {
405 ir_instruction
*ir
= (ir_instruction
*)iter
.get();
409 next_ir
->insert_before(v
.result
);
412 /* Generate the declarations for the parameters to our inlined code,
413 * and set up the mapping of real function body variables to ours.
416 param_iter
= this->actual_parameters
.iterator();
417 for (i
= 0; i
< num_parameters
; i
++) {
418 ir_instruction
*const param
= (ir_instruction
*) param_iter
.get();
420 /* Move the actual param into our param variable if it's an 'in' type. */
421 if (parameters
[i
]->mode
== ir_var_out
||
422 parameters
[i
]->mode
== ir_var_inout
) {
423 ir_assignment
*assign
;
425 assign
= new ir_assignment(param
->as_rvalue(),
426 new ir_dereference(parameters
[i
]),
428 next_ir
->insert_before(assign
);
437 return new ir_dereference(retval
);
443 ir_function_inlining_visitor::visit(ir_variable
*ir
)
450 ir_function_inlining_visitor::visit(ir_loop
*ir
)
452 do_function_inlining(&ir
->body_instructions
);
456 ir_function_inlining_visitor::visit(ir_loop_jump
*ir
)
463 ir_function_inlining_visitor::visit(ir_function_signature
*ir
)
465 do_function_inlining(&ir
->body
);
470 ir_function_inlining_visitor::visit(ir_function
*ir
)
472 foreach_iter(exec_list_iterator
, iter
, *ir
) {
473 ir_function_signature
*const sig
= (ir_function_signature
*) iter
.get();
479 ir_function_inlining_visitor::visit(ir_expression
*ir
)
481 unsigned int operand
;
483 for (operand
= 0; operand
< ir
->get_num_operands(); operand
++) {
484 ir
->operands
[operand
]->accept(this);
490 ir_function_inlining_visitor::visit(ir_swizzle
*ir
)
492 ir
->val
->accept(this);
497 ir_function_inlining_visitor::visit(ir_dereference
*ir
)
499 if (ir
->mode
== ir_dereference::ir_reference_array
) {
500 ir
->selector
.array_index
->accept(this);
502 ir
->var
->accept(this);
506 ir_function_inlining_visitor::visit(ir_assignment
*ir
)
508 ir
->rhs
->accept(this);
513 ir_function_inlining_visitor::visit(ir_constant
*ir
)
520 ir_function_inlining_visitor::visit(ir_call
*ir
)
527 ir_function_inlining_visitor::visit(ir_return
*ir
)
534 ir_function_inlining_visitor::visit(ir_if
*ir
)
536 ir
->condition
->accept(this);
538 do_function_inlining(&ir
->then_instructions
);
539 do_function_inlining(&ir
->else_instructions
);