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 "glsl_types.h"
36 class variable_remap
: public exec_node
{
38 variable_remap(const ir_variable
*old_var
, ir_variable
*new_var
)
39 : old_var(old_var
), new_var(new_var
)
43 const ir_variable
*old_var
;
47 class ir_function_cloning_visitor
: public ir_visitor
{
49 ir_function_cloning_visitor(ir_variable
*retval
)
55 virtual ~ir_function_cloning_visitor()
60 void remap_variable(const ir_variable
*old_var
, ir_variable
*new_var
) {
61 variable_remap
*remap
= new variable_remap(old_var
, new_var
);
62 this->remap_list
.push_tail(remap
);
65 ir_variable
*get_remapped_variable(ir_variable
*var
) {
66 foreach_iter(exec_list_iterator
, iter
, this->remap_list
) {
67 variable_remap
*remap
= (variable_remap
*)iter
.get();
69 if (var
== remap
->old_var
)
70 return remap
->new_var
;
73 /* Not a reapped variable, so a global scoped reference, for example. */
77 /* List of variable_remap for mapping from original function body variables
78 * to inlined function body variables.
82 /* Return value for the inlined function. */
88 * As typical for the visitor pattern, there must be one \c visit method for
89 * each concrete subclass of \c ir_instruction. Virtual base classes within
90 * the hierarchy should not have \c visit methods.
93 virtual void visit(ir_variable
*);
94 virtual void visit(ir_label
*);
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_label
*ir
)
130 ir_function_cloning_visitor::visit(ir_loop
*ir
)
137 ir_function_cloning_visitor::visit(ir_loop_jump
*ir
)
145 ir_function_cloning_visitor::visit(ir_function_signature
*ir
)
153 ir_function_cloning_visitor::visit(ir_function
*ir
)
160 ir_function_cloning_visitor::visit(ir_expression
*ir
)
162 unsigned int operand
;
163 ir_rvalue
*op
[2] = {NULL
, NULL
};
165 for (operand
= 0; operand
< ir
->get_num_operands(); operand
++) {
166 ir
->operands
[operand
]->accept(this);
167 op
[operand
] = this->result
->as_rvalue();
171 this->result
= new ir_expression(ir
->operation
, ir
->type
, op
[0], op
[1]);
176 ir_function_cloning_visitor::visit(ir_swizzle
*ir
)
178 ir
->val
->accept(this);
180 this->result
= new ir_swizzle(this->result
->as_rvalue(), ir
->mask
);
184 ir_function_cloning_visitor::visit(ir_dereference
*ir
)
186 if (ir
->mode
== ir_dereference::ir_reference_variable
) {
187 ir_variable
*old_var
= ir
->var
->as_variable();
189 /* If it's a deref of a real variable, then we need to remap it if
190 * it was local to the function.
193 ir_variable
*new_var
;
195 new_var
= this->get_remapped_variable(old_var
);
197 this->result
= new ir_dereference(new_var
);
199 ir
->var
->accept(this);
201 this->result
= new ir_dereference(this->result
);
209 ir_function_cloning_visitor::visit(ir_assignment
*ir
)
211 ir_rvalue
*lhs
, *rhs
, *condition
;
213 ir
->lhs
->accept(this);
214 lhs
= this->result
->as_rvalue();
216 ir
->rhs
->accept(this);
217 rhs
= this->result
->as_rvalue();
219 ir
->condition
->accept(this);
220 condition
= this->result
->as_rvalue();
222 this->result
= new ir_assignment(lhs
, rhs
, condition
);
227 ir_function_cloning_visitor::visit(ir_constant
*ir
)
229 this->result
= ir
->clone();
234 ir_function_cloning_visitor::visit(ir_call
*ir
)
236 exec_list parameters
;
238 foreach_iter(exec_list_iterator
, iter
, *ir
) {
239 ir_rvalue
*param
= (ir_rvalue
*)iter
.get();
242 parameters
.push_tail(this->result
);
245 this->result
= new ir_call(ir
->get_callee(), ¶meters
);
250 ir_function_cloning_visitor::visit(ir_return
*ir
)
254 assert(this->retval
);
256 rval
= ir
->get_value();
258 rval
= this->result
->as_rvalue();
261 result
= new ir_assignment(new ir_dereference(this->retval
),
262 ir
->get_value(), NULL
);
267 ir_function_cloning_visitor::visit(ir_if
*ir
)
274 can_inline(ir_call
*call
)
276 bool found_return
= false;
278 /* FINISHME: Right now we only allow a single statement that is a return.
280 foreach_iter(exec_list_iterator
, iter
, call
->get_callee()->body
) {
281 ir_instruction
*ir
= (ir_instruction
*)iter
.get();
282 if (ir
->get_next()->get_next() != NULL
)
285 if (!ir
->as_return())
295 do_function_inlining(exec_list
*instructions
)
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 /* Generate the declarations for the parameters to our inlined code,
392 * and set up the mapping of real function body variables to ours.
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 the actual param into our param variable if it's an 'in' 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_label
*ir
)
431 ir
->signature
->accept(this);
435 ir_function_inlining_visitor::visit(ir_loop
*ir
)
437 do_function_inlining(&ir
->body_instructions
);
441 ir_function_inlining_visitor::visit(ir_loop_jump
*ir
)
448 ir_function_inlining_visitor::visit(ir_function_signature
*ir
)
450 do_function_inlining(&ir
->body
);
455 ir_function_inlining_visitor::visit(ir_function
*ir
)
461 ir_function_inlining_visitor::visit(ir_expression
*ir
)
463 unsigned int operand
;
465 for (operand
= 0; operand
< ir
->get_num_operands(); operand
++) {
466 ir
->operands
[operand
]->accept(this);
472 ir_function_inlining_visitor::visit(ir_swizzle
*ir
)
474 ir
->val
->accept(this);
479 ir_function_inlining_visitor::visit(ir_dereference
*ir
)
481 if (ir
->mode
== ir_dereference::ir_reference_array
) {
482 ir
->selector
.array_index
->accept(this);
484 ir
->var
->accept(this);
488 ir_function_inlining_visitor::visit(ir_assignment
*ir
)
490 ir
->rhs
->accept(this);
495 ir_function_inlining_visitor::visit(ir_constant
*ir
)
502 ir_function_inlining_visitor::visit(ir_call
*ir
)
509 ir_function_inlining_visitor::visit(ir_return
*ir
)
516 ir_function_inlining_visitor::visit(ir_if
*ir
)
518 ir
->condition
->accept(this);
520 do_function_inlining(&ir
->then_instructions
);
521 do_function_inlining(&ir
->else_instructions
);