Reorder functions in dependency order
authorMikko Rasa <tdb@tdb.fi>
Sat, 16 Jun 2018 16:38:11 +0000 (19:38 +0300)
committerMikko Rasa <tdb@tdb.fi>
Sat, 16 Jun 2018 16:41:51 +0000 (19:41 +0300)
Otherwise the inliner might inline a function to a point before its
original definition.  This can break references to other functions
declared after the inlining point, causing the unused function eliminator
to eventually remove them.

source/programcompiler.cpp
source/programcompiler.h

index fbcc6598d3bcd5e7e74bf50bdf3762e51de9e343..0aed5936af82948eb1c040621e61b7dea83b2b18 100644 (file)
@@ -987,13 +987,30 @@ void ProgramCompiler::InterfaceGenerator::visit(Passthrough &pass)
 
 
 ProgramCompiler::DeclarationReorderer::DeclarationReorderer():
+       scope_level(0),
        kind(NO_DECLARATION)
 { }
 
+void ProgramCompiler::DeclarationReorderer::visit(FunctionCall &call)
+{
+       FunctionDeclaration *def = call.declaration;
+       if(def)
+               def = def->definition;
+       if(def && !ordered_funcs.count(def))
+               needed_funcs.insert(def);
+}
+
 void ProgramCompiler::DeclarationReorderer::visit(Block &block)
 {
+       SetForScope<unsigned> set(scope_level, scope_level+1);
+       if(scope_level>1)
+               return Visitor::visit(block);
+
        list<RefPtr<Node> >::iterator struct_insert_point = block.body.end();
        list<RefPtr<Node> >::iterator variable_insert_point = block.body.end();
+       list<RefPtr<Node> >::iterator function_insert_point = block.body.end();
+       unsigned unordered_func_count = 0;
+       bool ordered_any_funcs = false;
 
        for(list<RefPtr<Node> >::iterator i=block.body.begin(); i!=block.body.end(); )
        {
@@ -1017,13 +1034,64 @@ void ProgramCompiler::DeclarationReorderer::visit(Block &block)
                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 ProgramCompiler::DeclarationReorderer::visit(ProgramSyntax::VariableDeclaration &var)
+{
+       Visitor::visit(var);
+       kind = VARIABLE;
+}
+
+void ProgramCompiler::DeclarationReorderer::visit(FunctionDeclaration &func)
+{
+       needed_funcs.clear();
+       func.body.visit(*this);
+       needed_funcs.erase(&func);
+       kind = FUNCTION;
+}
+
 
 ProgramCompiler::InlineableFunctionLocator::InlineableFunctionLocator():
        in_function(0)
index b14c03d8021fa5fa4726aa9a9ef6b9cbbb94be1c..7e8d3373a53e4ffcf028a218d99e420d1a9cd5a7 100644 (file)
@@ -169,17 +169,21 @@ private:
                        FUNCTION
                };
 
+               unsigned scope_level;
                DeclarationKind kind;
+               std::set<ProgramSyntax::Node *> ordered_funcs;
+               std::set<ProgramSyntax::Node *> needed_funcs;
 
                DeclarationReorderer();
 
                using Visitor::visit;
                virtual void visit(ProgramSyntax::Block &);
+               virtual void visit(ProgramSyntax::FunctionCall &);
                virtual void visit(ProgramSyntax::InterfaceLayout &) { kind = LAYOUT; }
                virtual void visit(ProgramSyntax::StructDeclaration &) { kind = STRUCT; }
-               virtual void visit(ProgramSyntax::VariableDeclaration &) { kind = VARIABLE; }
+               virtual void visit(ProgramSyntax::VariableDeclaration &);
                virtual void visit(ProgramSyntax::InterfaceBlock &) { kind = VARIABLE; }
-               virtual void visit(ProgramSyntax::FunctionDeclaration &) { kind = FUNCTION; }
+               virtual void visit(ProgramSyntax::FunctionDeclaration &);
        };
 
        struct InlineableFunctionLocator: Visitor