]> git.tdb.fi Git - libs/gl.git/commitdiff
Refactor FunctionInliner to do any necessary declaration reordering
authorMikko Rasa <tdb@tdb.fi>
Mon, 1 Mar 2021 15:36:19 +0000 (17:36 +0200)
committerMikko Rasa <tdb@tdb.fi>
Mon, 1 Mar 2021 19:06:08 +0000 (21:06 +0200)
source/glsl/compiler.cpp
source/glsl/compiler.h
source/glsl/generate.cpp
source/glsl/generate.h
source/glsl/optimize.cpp
source/glsl/optimize.h
source/glsl/visitor.cpp
source/glsl/visitor.h

index cedd25e759bf2e48bf87b7afb27c10488e712fda..55a69f0df38ecaf1b681f9a698e6bbc2abed02da 100644 (file)
@@ -82,7 +82,7 @@ void Compiler::compile(Mode mode)
                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)
@@ -223,8 +223,6 @@ void Compiler::generate(Stage &stage, Mode mode)
                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);
@@ -235,7 +233,6 @@ void Compiler::generate(Stage &stage, Mode mode)
        InterfaceGenerator().apply(stage);
        VariableResolver().apply(stage);
 
-       DeclarationReorderer().apply(stage);
        FunctionResolver().apply(stage);
        ConstantSpecializer().apply(stage, (mode==PROGRAM && specialized ? &spec_values : 0));
        if(mode==PROGRAM)
@@ -246,7 +243,7 @@ Compiler::OptimizeResult Compiler::optimize(Stage &stage)
 {
        ConstantConditionEliminator().apply(stage);
 
-       FunctionInliner().apply(stage);
+       bool any_inlined = FunctionInliner().apply(stage);
        BlockHierarchyResolver().apply(stage);
        VariableResolver().apply(stage);
 
@@ -255,7 +252,7 @@ Compiler::OptimizeResult Compiler::optimize(Stage &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)
index 64cbac4f7cefd801d1c8f38667d488995a0cd6da..ec410c03ce45419c9a32de5cc6c0d5e27da5bd2a 100644 (file)
@@ -24,6 +24,7 @@ private:
        enum OptimizeResult
        {
                NEXT_STAGE,
+               REDO_STAGE,
                REDO_PREVIOUS
        };
 
index 2fa930a9df822ac369842d46045baaa8955fadd5..13f67d8cade070a4349bb2335080b27d1a2c790c 100644 (file)
@@ -655,111 +655,6 @@ void InterfaceGenerator::visit(Passthrough &pass)
        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
index 977ed156f4490ab9e282b328d59c6c88074db3f2..48fc742342bdf042aa32bdbd5686e61e1e43bbe0 100644 (file)
@@ -141,39 +141,6 @@ private:
        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
index 2215f8335cd06a23ea71e2c381cb1776362b81cd..40d1c26f97f5f4886c2c3db4d28c9627aa499eb6 100644 (file)
@@ -39,14 +39,54 @@ void InlineableFunctionLocator::visit(FunctionDeclaration &func)
 }
 
 
+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)
@@ -54,7 +94,10 @@ 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)
@@ -102,6 +145,9 @@ void FunctionInliner::visit(FunctionCall &call)
        {
                extract_result = 2;
                def->visit(*this);
+
+               if(inline_result)
+                       NodeReorderer().apply(*stage, *current_function, InlineDependencyCollector().apply(*def));
        }
        else
                inline_result = 0;
@@ -114,6 +160,12 @@ void FunctionInliner::visit(VariableDeclaration &var)
        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);
index ed016ca0b9ddd26dd5e8e871b25a0f15484e2881..eae90399542d3130ba38e08c24d87f6f13a7ff50 100644 (file)
@@ -11,8 +11,7 @@ namespace GL {
 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:
@@ -30,20 +29,39 @@ 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> &);
@@ -54,6 +72,7 @@ private:
        virtual void visit(MemberAccess &);
        virtual void visit(FunctionCall &);
        virtual void visit(VariableDeclaration &);
+       virtual void visit(FunctionDeclaration &);
        virtual void visit(Return &);
 };
 
index d8b1813959f17e4535ea1ea8c60001c22a36d76f..9bbd4914b1a0a289caa3c48a3504fa6c79e0c11d 100644 (file)
@@ -200,6 +200,39 @@ void NodeRemover::visit(Iteration &iter)
        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
index 83b310f62ebadbcef621a9b8d1aa65eb571e59c1..e0d74f6226927299913e3e9d41892042eb52f6bb 100644 (file)
@@ -110,6 +110,23 @@ private:
        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