void InlineableFunctionLocator::visit(FunctionDeclaration &func)
{
+ bool has_out_params = false;
+ for(NodeArray<VariableDeclaration>::const_iterator i=func.parameters.begin(); (!has_out_params && i!=func.parameters.end()); ++i)
+ has_out_params = ((*i)->interface=="out");
+
unsigned &count = refcounts[func.definition];
- if(count<=1 && func.parameters.empty())
+ if(count<=1 && !has_out_params)
inlineable.insert(func.definition);
SetForScope<FunctionDeclaration *> set(current_function, &func);
pass(DEPENDS)
{ }
-const string &InlineContentInjector::apply(Stage &stage, FunctionDeclaration &target_func, Block &tgt_blk, const NodeList<Statement>::iterator &ins_pt, FunctionDeclaration &src)
+const string &InlineContentInjector::apply(Stage &stage, FunctionDeclaration &target_func, Block &tgt_blk, const NodeList<Statement>::iterator &ins_pt, FunctionCall &call)
{
- source_func = &src;
+ source_func = call.declaration->definition;
// Collect all declarations the inlined function depends on.
pass = DEPENDS;
staging_block.variables.clear();
remap_prefix = source_func->name;
- for(NodeList<Statement>::iterator i=src.body.body.begin(); i!=src.body.body.end(); ++i)
+ std::vector<RefPtr<VariableDeclaration> > params;
+ params.reserve(source_func->parameters.size());
+ for(NodeArray<VariableDeclaration>::iterator i=source_func->parameters.begin(); i!=source_func->parameters.end(); ++i)
+ {
+ RefPtr<VariableDeclaration> var = (*i)->clone();
+ var->interface.clear();
+
+ SetForScope<Pass> set_pass(pass, RENAME);
+ var->visit(*this);
+
+ staging_block.body.push_back(0);
+ staging_block.body.back() = var;
+ params.push_back(var);
+ }
+
+ for(NodeList<Statement>::iterator i=source_func->body.body.begin(); i!=source_func->body.body.end(); ++i)
{
r_inlined_statement = 0;
(*i)->visit(*this);
remap_prefix = target_func.name;
target_func.visit(*this);
+ // Put the argument expressions in place after all renaming has been done.
+ for(unsigned i=0; i<source_func->parameters.size(); ++i)
+ params[i]->init_expression = call.arguments[i]->clone();
+
tgt_blk.body.splice(ins_pt, staging_block.body);
NodeReorderer().apply(stage, target_func, dependencies);
if(def && inlineable.count(def))
{
- string result_name = InlineContentInjector().apply(*stage, *current_function, *current_block, insert_point, *def);
+ string result_name = InlineContentInjector().apply(*stage, *current_function, *current_block, insert_point, call);
// This will later get removed by UnusedVariableRemover.
if(result_name.empty())
namespace SL {
/** Finds functions which are candidates for inlining. Currently this means
-functions which have no parameters, contain no more than one return statement,
-and are only called once. */
+functions which have no flow control statements, no more than one return
+statement, and are only called once. */
class InlineableFunctionLocator: private TraversingVisitor
{
private:
public:
InlineContentInjector();
- const std::string &apply(Stage &, FunctionDeclaration &, Block &, const NodeList<Statement>::iterator &, FunctionDeclaration &);
+ const std::string &apply(Stage &, FunctionDeclaration &, Block &, const NodeList<Statement>::iterator &, FunctionCall &);
private:
virtual void visit(VariableReference &);
/* Expected output: fragment
uniform sampler2D tex;
-vec3 srgb_to_linear(vec3 color)
-{
- return mix(color.rgb/12.92, pow((color.rgb+0.055)/1.055, vec3(2.4)), lessThan(color, vec3(0.04045)));
-}
-vec4 srgb_to_linear(vec4 color)
-{
- return vec4(srgb_to_linear(color.rgb), color.a);
-}
layout(location=0) out vec4 frag_color;
in vec2 _vs_out_texcoord;
void main()
{
- frag_color = srgb_to_linear(texture(tex, _vs_out_texcoord));
+ vec4 color = texture(tex, _vs_out_texcoord);
+ vec3 _srgb_to_linear_color = color.rgb;
+ frag_color = vec4(mix(_srgb_to_linear_color.rgb/12.92, pow((_srgb_to_linear_color.rgb+0.055)/1.055, vec3(2.4)), lessThan(_srgb_to_linear_color, vec3(0.04045))), color.a);
}
*/