OptimizeResult result = optimize(*i);
if(result==REDO_PREVIOUS)
i = module->stages.begin();
- else
+ else if(result!=REDO_STAGE)
++i;
}
for(list<Stage>::iterator i=module->stages.begin(); i!=module->stages.end(); ++i)
stage.required_features.glsl_version = module->shared.required_features.glsl_version;
inject_block(stage.content, module->shared.content);
- DeclarationReorderer().apply(stage);
-
// Initial resolving pass
BlockHierarchyResolver().apply(stage);
FunctionResolver().apply(stage);
InterfaceGenerator().apply(stage);
VariableResolver().apply(stage);
- DeclarationReorderer().apply(stage);
FunctionResolver().apply(stage);
ConstantSpecializer().apply(stage, (mode==PROGRAM && specialized ? &spec_values : 0));
if(mode==PROGRAM)
{
ConstantConditionEliminator().apply(stage);
- FunctionInliner().apply(stage);
+ bool any_inlined = FunctionInliner().apply(stage);
BlockHierarchyResolver().apply(stage);
VariableResolver().apply(stage);
bool any_removed = UnusedVariableRemover().apply(stage);
any_removed |= UnusedFunctionRemover().apply(stage);
- return any_removed ? REDO_PREVIOUS : NEXT_STAGE;
+ return any_removed ? REDO_PREVIOUS : any_inlined ? REDO_STAGE : NEXT_STAGE;
}
void Compiler::finalize(Stage &stage, Mode mode)
enum OptimizeResult
{
NEXT_STAGE,
+ REDO_STAGE,
REDO_PREVIOUS
};
nodes_to_remove.insert(&pass);
}
-
-DeclarationReorderer::DeclarationReorderer():
- kind(NO_DECLARATION)
-{ }
-
-void DeclarationReorderer::visit(FunctionCall &call)
-{
- FunctionDeclaration *def = call.declaration;
- if(def)
- def = def->definition;
- if(def && !ordered_funcs.count(def))
- needed_funcs.insert(def);
-}
-
-void DeclarationReorderer::visit(Block &block)
-{
- if(block.parent)
- return TraversingVisitor::visit(block);
-
- NodeList<Statement>::iterator struct_insert_point = block.body.end();
- NodeList<Statement>::iterator variable_insert_point = block.body.end();
- NodeList<Statement>::iterator function_insert_point = block.body.end();
- unsigned unordered_func_count = 0;
- bool ordered_any_funcs = false;
-
- for(NodeList<Statement>::iterator i=block.body.begin(); i!=block.body.end(); )
- {
- kind = NO_DECLARATION;
- (*i)->visit(*this);
-
- bool moved = false;
- if(kind==STRUCT && struct_insert_point!=block.body.end())
- {
- block.body.insert(struct_insert_point, *i);
- moved = true;
- }
- else if(kind>STRUCT && struct_insert_point==block.body.end())
- struct_insert_point = i;
-
- if(kind==VARIABLE && variable_insert_point!=block.body.end())
- {
- block.body.insert(variable_insert_point, *i);
- moved = true;
- }
- else if(kind>VARIABLE && variable_insert_point==block.body.end())
- variable_insert_point = i;
-
- if(kind==FUNCTION)
- {
- if(function_insert_point==block.body.end())
- function_insert_point = i;
-
- if(needed_funcs.empty())
- {
- ordered_funcs.insert(i->get());
- if(i!=function_insert_point)
- {
- block.body.insert(function_insert_point, *i);
- moved = true;
- }
- else
- ++function_insert_point;
- ordered_any_funcs = true;
- }
- else
- ++unordered_func_count;
- }
-
- if(moved)
- {
- if(function_insert_point==i)
- ++function_insert_point;
- block.body.erase(i++);
- }
- else
- ++i;
-
- if(i==block.body.end() && unordered_func_count)
- {
- if(!ordered_any_funcs)
- // A subset of the remaining functions forms a recursive loop
- /* TODO pick a function and move it up, adding any necessary
- declarations */
- break;
-
- i = function_insert_point;
- unordered_func_count = 0;
- }
- }
-}
-
-void DeclarationReorderer::visit(VariableDeclaration &var)
-{
- TraversingVisitor::visit(var);
- kind = VARIABLE;
-}
-
-void DeclarationReorderer::visit(FunctionDeclaration &func)
-{
- needed_funcs.clear();
- func.body.visit(*this);
- needed_funcs.erase(&func);
- kind = FUNCTION;
-}
-
} // namespace SL
} // namespace GL
} // namespace Msp
virtual void visit(Passthrough &);
};
-/** Reorders declarations to ensure that declarations always appear before
-references. */
-class DeclarationReorderer: private TraversingVisitor
-{
-private:
- enum DeclarationKind
- {
- NO_DECLARATION,
- LAYOUT,
- STRUCT,
- VARIABLE,
- FUNCTION
- };
-
- DeclarationKind kind;
- std::set<Node *> ordered_funcs;
- std::set<Node *> needed_funcs;
-
-public:
- DeclarationReorderer();
-
- void apply(Stage &s) { s.content.visit(*this); }
-
-private:
- virtual void visit(Block &);
- virtual void visit(FunctionCall &);
- virtual void visit(InterfaceLayout &) { kind = LAYOUT; }
- virtual void visit(StructDeclaration &) { kind = STRUCT; }
- virtual void visit(VariableDeclaration &);
- virtual void visit(InterfaceBlock &) { kind = VARIABLE; }
- virtual void visit(FunctionDeclaration &);
-};
-
} // namespace SL
} // namespace GL
} // namespace Msp
}
+void InlineDependencyCollector::visit(VariableReference &var)
+{
+ if(var.declaration)
+ {
+ dependencies.insert(var.declaration);
+ var.declaration->visit(*this);
+ }
+}
+
+void InlineDependencyCollector::visit(InterfaceBlockReference &iface)
+{
+ if(iface.declaration)
+ {
+ dependencies.insert(iface.declaration);
+ iface.declaration->visit(*this);
+ }
+}
+
+void InlineDependencyCollector::visit(FunctionCall &call)
+{
+ if(call.declaration)
+ dependencies.insert(call.declaration);
+ TraversingVisitor::visit(call);
+}
+
+void InlineDependencyCollector::visit(VariableDeclaration &var)
+{
+ if(var.type_declaration)
+ {
+ dependencies.insert(var.type_declaration);
+ var.type_declaration->visit(*this);
+ }
+}
+
+
FunctionInliner::FunctionInliner():
- extract_result(0)
+ current_function(0),
+ extract_result(0),
+ any_inlined(false)
{ }
-void FunctionInliner::apply(Stage &stage)
+bool FunctionInliner::apply(Stage &s)
{
- inlineable = InlineableFunctionLocator().apply(stage);
- stage.content.visit(*this);
+ stage = &s;
+ inlineable = InlineableFunctionLocator().apply(s);
+ any_inlined = false;
+ s.content.visit(*this);
+ return any_inlined;
}
void FunctionInliner::visit_and_inline(RefPtr<Expression> &ptr)
inline_result = 0;
ptr->visit(*this);
if(inline_result)
+ {
ptr = inline_result;
+ any_inlined = true;
+ }
}
void FunctionInliner::visit(Block &block)
{
extract_result = 2;
def->visit(*this);
+
+ if(inline_result)
+ NodeReorderer().apply(*stage, *current_function, InlineDependencyCollector().apply(*def));
}
else
inline_result = 0;
inline_result = 0;
}
+void FunctionInliner::visit(FunctionDeclaration &func)
+{
+ SetForScope<FunctionDeclaration *> set_func(current_function, &func);
+ TraversingVisitor::visit(func);
+}
+
void FunctionInliner::visit(Return &ret)
{
TraversingVisitor::visit(ret);
namespace SL {
/** Finds functions which are candidates for inlining. Currently this means
-functions which have no parameters, are only called once, and that call occurs
-after the definition of the function. */
+functions which have no parameters and are only called once. */
class InlineableFunctionLocator: private TraversingVisitor
{
private:
virtual void visit(FunctionDeclaration &);
};
+/** Collects declarations referenced by a function. */
+class InlineDependencyCollector: private TraversingVisitor
+{
+private:
+ std::set<Node *> dependencies;
+
+public:
+ const std::set<Node *> &apply(FunctionDeclaration &f) { f.visit(*this); return dependencies; }
+
+private:
+ virtual void visit(VariableReference &);
+ virtual void visit(InterfaceBlockReference &);
+ virtual void visit(FunctionCall &);
+ virtual void visit(VariableDeclaration &);
+};
+
/** Inlines functions. Internally uses InlineableFunctionLocator to find
candidate functions. Only functions which consist of a single return statement
are inlined. */
class FunctionInliner: private TraversingVisitor
{
private:
+ Stage *stage;
std::set<FunctionDeclaration *> inlineable;
+ FunctionDeclaration *current_function;
unsigned extract_result;
RefPtr<Expression> inline_result;
+ bool any_inlined;
public:
FunctionInliner();
- void apply(Stage &);
+ bool apply(Stage &);
private:
void visit_and_inline(RefPtr<Expression> &);
virtual void visit(MemberAccess &);
virtual void visit(FunctionCall &);
virtual void visit(VariableDeclaration &);
+ virtual void visit(FunctionDeclaration &);
virtual void visit(Return &);
};
TraversingVisitor::visit(iter);
}
+
+NodeReorderer::NodeReorderer():
+ reorder_before(0),
+ to_reorder(0)
+{ }
+
+void NodeReorderer::apply(Stage &stage, Node &before, const set<Node *> &tr)
+{
+ reorder_before = &before;
+ to_reorder = &tr;
+ stage.content.visit(*this);
+}
+
+void NodeReorderer::visit(Block &block)
+{
+ NodeList<Statement>::iterator insert_point = block.body.end();
+ for(NodeList<Statement>::iterator i=block.body.begin(); i!=block.body.end(); )
+ {
+ (*i)->visit(*this);
+ if(insert_point!=block.body.end() && to_reorder->count(i->get()))
+ {
+ NodeList<Statement>::iterator j = i++;
+ block.body.splice(insert_point, block.body, j);
+ }
+ else
+ {
+ if(i->get()==reorder_before)
+ insert_point = i;
+ ++i;
+ }
+ }
+}
+
} // namespace SL
} // namespace GL
} // namespace Msp
virtual void visit(Iteration &);
};
+/** Reorders a set of nodes so they appear before another node. Only nodes
+on the same hierarchly level as the target node are reordered. */
+class NodeReorderer: private TraversingVisitor
+{
+private:
+ Node *reorder_before;
+ const std::set<Node *> *to_reorder;
+
+public:
+ NodeReorderer();
+
+ void apply(Stage &, Node &, const std::set<Node *> &);
+
+private:
+ virtual void visit(Block &);
+};
+
} // namespace SL
} // namespace GL
} // namespace Msp