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.
31 #include "ir_visitor.h"
32 #include "ir_function_inlining.h"
33 #include "ir_expression_flattening.h"
34 #include "glsl_types.h"
36 class ir_function_inlining_visitor
: public ir_hierarchical_visitor
{
38 ir_function_inlining_visitor()
43 virtual ~ir_function_inlining_visitor()
48 virtual ir_visitor_status
visit_enter(ir_expression
*);
49 virtual ir_visitor_status
visit_enter(ir_call
*);
50 virtual ir_visitor_status
visit_enter(ir_assignment
*);
51 virtual ir_visitor_status
visit_enter(ir_return
*);
52 virtual ir_visitor_status
visit_enter(ir_texture
*);
53 virtual ir_visitor_status
visit_enter(ir_swizzle
*);
58 class variable_remap
: public exec_node
{
60 variable_remap(const ir_variable
*old_var
, ir_variable
*new_var
)
61 : old_var(old_var
), new_var(new_var
)
65 const ir_variable
*old_var
;
69 class ir_function_cloning_visitor
: public ir_visitor
{
71 ir_function_cloning_visitor(ir_variable
*retval
)
77 virtual ~ir_function_cloning_visitor()
82 void remap_variable(const ir_variable
*old_var
, ir_variable
*new_var
) {
83 variable_remap
*remap
= new variable_remap(old_var
, new_var
);
84 this->remap_list
.push_tail(remap
);
87 ir_variable
*get_remapped_variable(ir_variable
*var
) {
88 foreach_iter(exec_list_iterator
, iter
, this->remap_list
) {
89 variable_remap
*remap
= (variable_remap
*)iter
.get();
91 if (var
== remap
->old_var
)
92 return remap
->new_var
;
95 /* Not a reapped variable, so a global scoped reference, for example. */
99 /* List of variable_remap for mapping from original function body variables
100 * to inlined function body variables.
102 exec_list remap_list
;
104 /* Return value for the inlined function. */
108 * \name Visit methods
110 * As typical for the visitor pattern, there must be one \c visit method for
111 * each concrete subclass of \c ir_instruction. Virtual base classes within
112 * the hierarchy should not have \c visit methods.
115 virtual void visit(ir_variable
*);
116 virtual void visit(ir_loop
*);
117 virtual void visit(ir_loop_jump
*);
118 virtual void visit(ir_function_signature
*);
119 virtual void visit(ir_function
*);
120 virtual void visit(ir_expression
*);
121 virtual void visit(ir_texture
*);
122 virtual void visit(ir_swizzle
*);
123 virtual void visit(ir_dereference_variable
*);
124 virtual void visit(ir_dereference_array
*);
125 virtual void visit(ir_dereference_record
*);
126 virtual void visit(ir_assignment
*);
127 virtual void visit(ir_constant
*);
128 virtual void visit(ir_call
*);
129 virtual void visit(ir_return
*);
130 virtual void visit(ir_if
*);
133 ir_instruction
*result
;
137 ir_function_cloning_visitor::visit(ir_variable
*ir
)
139 ir_variable
*new_var
= ir
->clone();
141 this->result
= new_var
;
143 this->remap_variable(ir
, new_var
);
147 ir_function_cloning_visitor::visit(ir_loop
*ir
)
149 /* FINISHME: Implement loop cloning. */
157 ir_function_cloning_visitor::visit(ir_loop_jump
*ir
)
159 /* FINISHME: Implement loop cloning. */
168 ir_function_cloning_visitor::visit(ir_function_signature
*ir
)
177 ir_function_cloning_visitor::visit(ir_function
*ir
)
185 ir_function_cloning_visitor::visit(ir_expression
*ir
)
187 unsigned int operand
;
188 ir_rvalue
*op
[2] = {NULL
, NULL
};
190 for (operand
= 0; operand
< ir
->get_num_operands(); operand
++) {
191 ir
->operands
[operand
]->accept(this);
192 op
[operand
] = this->result
->as_rvalue();
196 this->result
= new ir_expression(ir
->operation
, ir
->type
, op
[0], op
[1]);
201 ir_function_cloning_visitor::visit(ir_texture
*ir
)
203 ir_texture
*tex
= new ir_texture(ir
->op
);
205 ir
->sampler
->accept(this);
206 tex
->set_sampler(this->result
->as_dereference());
208 ir
->coordinate
->accept(this);
209 tex
->coordinate
= this->result
->as_rvalue();
211 if (ir
->projector
!= NULL
) {
212 ir
->projector
->accept(this);
213 tex
->projector
= this->result
->as_rvalue();
216 if (ir
->shadow_comparitor
!= NULL
) {
217 ir
->shadow_comparitor
->accept(this);
218 tex
->shadow_comparitor
= this->result
->as_rvalue();
221 for (int i
= 0; i
< 3; i
++)
222 tex
->offsets
[i
] = ir
->offsets
[i
];
224 tex
->lod_info
= ir
->lod_info
;
229 ir_function_cloning_visitor::visit(ir_swizzle
*ir
)
231 ir
->val
->accept(this);
233 this->result
= new ir_swizzle(this->result
->as_rvalue(), ir
->mask
);
237 ir_function_cloning_visitor::visit(ir_dereference_variable
*ir
)
239 ir_variable
*var
= this->get_remapped_variable(ir
->variable_referenced());
240 this->result
= new ir_dereference_variable(var
);
244 ir_function_cloning_visitor::visit(ir_dereference_array
*ir
)
246 ir
->array
->accept(this);
248 ir_rvalue
*var
= this->result
->as_rvalue();
250 ir
->array_index
->accept(this);
252 ir_rvalue
*index
= this->result
->as_rvalue();
254 this->result
= new ir_dereference_array(var
, index
);
258 ir_function_cloning_visitor::visit(ir_dereference_record
*ir
)
260 ir
->record
->accept(this);
262 ir_rvalue
*var
= this->result
->as_rvalue();
264 this->result
= new ir_dereference_record(var
, strdup(ir
->field
));
268 ir_function_cloning_visitor::visit(ir_assignment
*ir
)
270 ir_rvalue
*lhs
, *rhs
, *condition
= NULL
;
272 ir
->lhs
->accept(this);
273 lhs
= this->result
->as_rvalue();
275 ir
->rhs
->accept(this);
276 rhs
= this->result
->as_rvalue();
279 ir
->condition
->accept(this);
280 condition
= this->result
->as_rvalue();
283 this->result
= new ir_assignment(lhs
, rhs
, condition
);
288 ir_function_cloning_visitor::visit(ir_constant
*ir
)
290 this->result
= ir
->clone();
295 ir_function_cloning_visitor::visit(ir_call
*ir
)
297 exec_list parameters
;
299 foreach_iter(exec_list_iterator
, iter
, *ir
) {
300 ir_rvalue
*param
= (ir_rvalue
*)iter
.get();
303 parameters
.push_tail(this->result
);
306 this->result
= new ir_call(ir
->get_callee(), ¶meters
);
311 ir_function_cloning_visitor::visit(ir_return
*ir
)
315 assert(this->retval
);
317 rval
= ir
->get_value();
319 rval
= this->result
->as_rvalue();
322 result
= new ir_assignment(new ir_dereference_variable(this->retval
), rval
,
328 ir_function_cloning_visitor::visit(ir_if
*ir
)
330 /* FINISHME: Implement if cloning. */
338 automatic_inlining_predicate(ir_instruction
*ir
)
340 ir_call
*call
= ir
->as_call();
342 if (call
&& can_inline(call
))
349 do_function_inlining(exec_list
*instructions
)
351 ir_function_inlining_visitor v
;
353 do_expression_flattening(instructions
, automatic_inlining_predicate
);
361 ir_call::generate_inline(ir_instruction
*next_ir
)
363 ir_variable
**parameters
;
366 ir_variable
*retval
= NULL
;
369 foreach_iter(exec_list_iterator
, iter_sig
, this->callee
->parameters
)
372 parameters
= new ir_variable
*[num_parameters
];
374 /* Generate storage for the return value. */
375 if (this->callee
->return_type
) {
376 retval
= new ir_variable(this->callee
->return_type
, "__retval");
377 next_ir
->insert_before(retval
);
380 ir_function_cloning_visitor v
= ir_function_cloning_visitor(retval
);
382 /* Generate the declarations for the parameters to our inlined code,
383 * and set up the mapping of real function body variables to ours.
386 exec_list_iterator sig_param_iter
= this->callee
->parameters
.iterator();
387 exec_list_iterator param_iter
= this->actual_parameters
.iterator();
388 for (i
= 0; i
< num_parameters
; i
++) {
389 const ir_variable
*const sig_param
= (ir_variable
*) sig_param_iter
.get();
390 ir_rvalue
*param
= (ir_rvalue
*) param_iter
.get();
392 /* Generate a new variable for the parameter. */
393 parameters
[i
] = sig_param
->clone();
394 next_ir
->insert_before(parameters
[i
]);
396 v
.remap_variable(sig_param
, parameters
[i
]);
398 /* Move the actual param into our param variable if it's an 'in' type. */
399 if (parameters
[i
]->mode
== ir_var_in
||
400 parameters
[i
]->mode
== ir_var_inout
) {
401 ir_assignment
*assign
;
403 assign
= new ir_assignment(new ir_dereference_variable(parameters
[i
]),
405 next_ir
->insert_before(assign
);
408 sig_param_iter
.next();
412 /* Generate the inlined body of the function. */
413 foreach_iter(exec_list_iterator
, iter
, callee
->body
) {
414 ir_instruction
*ir
= (ir_instruction
*)iter
.get();
418 next_ir
->insert_before(v
.result
);
421 /* Copy back the value of any 'out' parameters from the function body
422 * variables to our own.
425 param_iter
= this->actual_parameters
.iterator();
426 for (i
= 0; i
< num_parameters
; i
++) {
427 ir_instruction
*const param
= (ir_instruction
*) param_iter
.get();
429 /* Move our param variable into the actual param if it's an 'out' type. */
430 if (parameters
[i
]->mode
== ir_var_out
||
431 parameters
[i
]->mode
== ir_var_inout
) {
432 ir_assignment
*assign
;
434 assign
= new ir_assignment(param
->as_rvalue(),
435 new ir_dereference_variable(parameters
[i
]),
437 next_ir
->insert_before(assign
);
443 delete [] parameters
;
446 return new ir_dereference_variable(retval
);
453 ir_function_inlining_visitor::visit_enter(ir_expression
*ir
)
456 return visit_continue_with_parent
;
461 ir_function_inlining_visitor::visit_enter(ir_return
*ir
)
464 return visit_continue_with_parent
;
469 ir_function_inlining_visitor::visit_enter(ir_texture
*ir
)
472 return visit_continue_with_parent
;
477 ir_function_inlining_visitor::visit_enter(ir_swizzle
*ir
)
480 return visit_continue_with_parent
;
485 ir_function_inlining_visitor::visit_enter(ir_call
*ir
)
487 if (can_inline(ir
)) {
488 (void) ir
->generate_inline(ir
);
490 this->progress
= true;
493 return visit_continue
;
498 ir_function_inlining_visitor::visit_enter(ir_assignment
*ir
)
500 ir_call
*call
= ir
->rhs
->as_call();
501 if (!call
|| !can_inline(call
))
502 return visit_continue
;
504 /* generates the parameter setup, function body, and returns the return
505 * value of the function
507 ir_rvalue
*rhs
= call
->generate_inline(ir
);
511 this->progress
= true;
513 return visit_continue
;