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
)
125 /* FINISHME: Implement loop cloning. */
133 ir_function_cloning_visitor::visit(ir_loop_jump
*ir
)
135 /* FINISHME: Implement loop cloning. */
144 ir_function_cloning_visitor::visit(ir_function_signature
*ir
)
153 ir_function_cloning_visitor::visit(ir_function
*ir
)
161 ir_function_cloning_visitor::visit(ir_expression
*ir
)
163 unsigned int operand
;
164 ir_rvalue
*op
[2] = {NULL
, NULL
};
166 for (operand
= 0; operand
< ir
->get_num_operands(); operand
++) {
167 ir
->operands
[operand
]->accept(this);
168 op
[operand
] = this->result
->as_rvalue();
172 this->result
= new ir_expression(ir
->operation
, ir
->type
, op
[0], op
[1]);
177 ir_function_cloning_visitor::visit(ir_swizzle
*ir
)
179 ir
->val
->accept(this);
181 this->result
= new ir_swizzle(this->result
->as_rvalue(), ir
->mask
);
185 ir_function_cloning_visitor::visit(ir_dereference
*ir
)
187 ir_variable
*old_var
= ir
->var
->as_variable();
191 var
= this->get_remapped_variable(old_var
);
193 ir
->var
->accept(this);
197 if (ir
->mode
== ir_dereference::ir_reference_variable
) {
198 this->result
= new ir_dereference(var
);
199 } else if (ir
->mode
== ir_dereference::ir_reference_array
) {
202 ir
->selector
.array_index
->accept(this);
203 index
= this->result
->as_rvalue();
205 this->result
= new ir_dereference(var
, index
);
207 assert(ir
->mode
== ir_dereference::ir_reference_record
);
208 this->result
= new ir_dereference(var
, strdup(ir
->selector
.field
));
213 ir_function_cloning_visitor::visit(ir_assignment
*ir
)
215 ir_rvalue
*lhs
, *rhs
, *condition
= NULL
;
217 ir
->lhs
->accept(this);
218 lhs
= this->result
->as_rvalue();
220 ir
->rhs
->accept(this);
221 rhs
= this->result
->as_rvalue();
224 ir
->condition
->accept(this);
225 condition
= this->result
->as_rvalue();
228 this->result
= new ir_assignment(lhs
, rhs
, condition
);
233 ir_function_cloning_visitor::visit(ir_constant
*ir
)
235 this->result
= ir
->clone();
240 ir_function_cloning_visitor::visit(ir_call
*ir
)
242 exec_list parameters
;
244 foreach_iter(exec_list_iterator
, iter
, *ir
) {
245 ir_rvalue
*param
= (ir_rvalue
*)iter
.get();
248 parameters
.push_tail(this->result
);
251 this->result
= new ir_call(ir
->get_callee(), ¶meters
);
256 ir_function_cloning_visitor::visit(ir_return
*ir
)
260 assert(this->retval
);
262 rval
= ir
->get_value();
264 rval
= this->result
->as_rvalue();
267 result
= new ir_assignment(new ir_dereference(this->retval
), rval
, NULL
);
272 ir_function_cloning_visitor::visit(ir_if
*ir
)
274 /* FINISHME: Implement if cloning. */
282 automatic_inlining_predicate(ir_instruction
*ir
)
284 ir_call
*call
= ir
->as_call();
286 if (call
&& can_inline(call
))
293 do_function_inlining(exec_list
*instructions
)
295 bool progress
= false;
297 do_expression_flattening(instructions
, automatic_inlining_predicate
);
299 foreach_iter(exec_list_iterator
, iter
, *instructions
) {
300 ir_instruction
*ir
= (ir_instruction
*)iter
.get();
301 ir_assignment
*assign
= ir
->as_assignment();
305 call
= assign
->rhs
->as_call();
306 if (!call
|| !can_inline(call
))
309 /* generates the parameter setup, function body, and returns the return
310 * value of the function
312 ir_rvalue
*rhs
= call
->generate_inline(ir
);
317 } else if ((call
= ir
->as_call()) && can_inline(call
)) {
318 (void)call
->generate_inline(ir
);
322 ir_function_inlining_visitor v
;
331 ir_call::generate_inline(ir_instruction
*next_ir
)
333 ir_variable
**parameters
;
336 ir_variable
*retval
= NULL
;
339 foreach_iter(exec_list_iterator
, iter_sig
, this->callee
->parameters
)
342 parameters
= new ir_variable
*[num_parameters
];
344 /* Generate storage for the return value. */
345 if (this->callee
->return_type
) {
346 retval
= new ir_variable(this->callee
->return_type
, "__retval");
347 next_ir
->insert_before(retval
);
350 ir_function_cloning_visitor v
= ir_function_cloning_visitor(retval
);
352 /* Generate the declarations for the parameters to our inlined code,
353 * and set up the mapping of real function body variables to ours.
356 exec_list_iterator sig_param_iter
= this->callee
->parameters
.iterator();
357 exec_list_iterator param_iter
= this->actual_parameters
.iterator();
358 for (i
= 0; i
< num_parameters
; i
++) {
359 const ir_variable
*const sig_param
= (ir_variable
*) sig_param_iter
.get();
360 ir_rvalue
*param
= (ir_rvalue
*) param_iter
.get();
362 /* Generate a new variable for the parameter. */
363 parameters
[i
] = sig_param
->clone();
364 next_ir
->insert_before(parameters
[i
]);
366 v
.remap_variable(sig_param
, parameters
[i
]);
368 /* Move the actual param into our param variable if it's an 'in' type. */
369 if (parameters
[i
]->mode
== ir_var_in
||
370 parameters
[i
]->mode
== ir_var_inout
) {
371 ir_assignment
*assign
;
373 assign
= new ir_assignment(new ir_dereference(parameters
[i
]),
375 next_ir
->insert_before(assign
);
378 sig_param_iter
.next();
382 /* Generate the inlined body of the function. */
383 foreach_iter(exec_list_iterator
, iter
, callee
->body
) {
384 ir_instruction
*ir
= (ir_instruction
*)iter
.get();
388 next_ir
->insert_before(v
.result
);
391 /* Copy back the value of any 'out' parameters from the function body
392 * variables to our own.
395 param_iter
= this->actual_parameters
.iterator();
396 for (i
= 0; i
< num_parameters
; i
++) {
397 ir_instruction
*const param
= (ir_instruction
*) param_iter
.get();
399 /* Move our param variable into the actual param if it's an 'out' type. */
400 if (parameters
[i
]->mode
== ir_var_out
||
401 parameters
[i
]->mode
== ir_var_inout
) {
402 ir_assignment
*assign
;
404 assign
= new ir_assignment(param
->as_rvalue(),
405 new ir_dereference(parameters
[i
]),
407 next_ir
->insert_before(assign
);
416 return new ir_dereference(retval
);
422 ir_function_inlining_visitor::visit(ir_variable
*ir
)
429 ir_function_inlining_visitor::visit(ir_loop
*ir
)
431 do_function_inlining(&ir
->body_instructions
);
435 ir_function_inlining_visitor::visit(ir_loop_jump
*ir
)
442 ir_function_inlining_visitor::visit(ir_function_signature
*ir
)
444 do_function_inlining(&ir
->body
);
449 ir_function_inlining_visitor::visit(ir_function
*ir
)
451 foreach_iter(exec_list_iterator
, iter
, *ir
) {
452 ir_function_signature
*const sig
= (ir_function_signature
*) iter
.get();
458 ir_function_inlining_visitor::visit(ir_expression
*ir
)
460 unsigned int operand
;
462 for (operand
= 0; operand
< ir
->get_num_operands(); operand
++) {
463 ir
->operands
[operand
]->accept(this);
469 ir_function_inlining_visitor::visit(ir_swizzle
*ir
)
471 ir
->val
->accept(this);
476 ir_function_inlining_visitor::visit(ir_dereference
*ir
)
478 if (ir
->mode
== ir_dereference::ir_reference_array
) {
479 ir
->selector
.array_index
->accept(this);
481 ir
->var
->accept(this);
485 ir_function_inlining_visitor::visit(ir_assignment
*ir
)
487 ir
->rhs
->accept(this);
492 ir_function_inlining_visitor::visit(ir_constant
*ir
)
499 ir_function_inlining_visitor::visit(ir_call
*ir
)
506 ir_function_inlining_visitor::visit(ir_return
*ir
)
513 ir_function_inlining_visitor::visit(ir_if
*ir
)
515 ir
->condition
->accept(this);
517 do_function_inlining(&ir
->then_instructions
);
518 do_function_inlining(&ir
->else_instructions
);