From 518f751d385b733adbf43fe4056403740709edec Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Mon, 1 Mar 2021 17:36:19 +0200 Subject: [PATCH] Refactor FunctionInliner to do any necessary declaration reordering --- source/glsl/compiler.cpp | 9 ++-- source/glsl/compiler.h | 1 + source/glsl/generate.cpp | 105 --------------------------------------- source/glsl/generate.h | 33 ------------ source/glsl/optimize.cpp | 60 ++++++++++++++++++++-- source/glsl/optimize.h | 25 ++++++++-- source/glsl/visitor.cpp | 33 ++++++++++++ source/glsl/visitor.h | 17 +++++++ 8 files changed, 132 insertions(+), 151 deletions(-) diff --git a/source/glsl/compiler.cpp b/source/glsl/compiler.cpp index cedd25e7..55a69f0d 100644 --- a/source/glsl/compiler.cpp +++ b/source/glsl/compiler.cpp @@ -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::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) diff --git a/source/glsl/compiler.h b/source/glsl/compiler.h index 64cbac4f..ec410c03 100644 --- a/source/glsl/compiler.h +++ b/source/glsl/compiler.h @@ -24,6 +24,7 @@ private: enum OptimizeResult { NEXT_STAGE, + REDO_STAGE, REDO_PREVIOUS }; diff --git a/source/glsl/generate.cpp b/source/glsl/generate.cpp index 2fa930a9..13f67d8c 100644 --- a/source/glsl/generate.cpp +++ b/source/glsl/generate.cpp @@ -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::iterator struct_insert_point = block.body.end(); - NodeList::iterator variable_insert_point = block.body.end(); - NodeList::iterator function_insert_point = block.body.end(); - unsigned unordered_func_count = 0; - bool ordered_any_funcs = false; - - for(NodeList::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 diff --git a/source/glsl/generate.h b/source/glsl/generate.h index 977ed156..48fc7423 100644 --- a/source/glsl/generate.h +++ b/source/glsl/generate.h @@ -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 ordered_funcs; - std::set 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 diff --git a/source/glsl/optimize.cpp b/source/glsl/optimize.cpp index 2215f833..40d1c26f 100644 --- a/source/glsl/optimize.cpp +++ b/source/glsl/optimize.cpp @@ -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 &ptr) @@ -54,7 +94,10 @@ void FunctionInliner::visit_and_inline(RefPtr &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 set_func(current_function, &func); + TraversingVisitor::visit(func); +} + void FunctionInliner::visit(Return &ret) { TraversingVisitor::visit(ret); diff --git a/source/glsl/optimize.h b/source/glsl/optimize.h index ed016ca0..eae90399 100644 --- a/source/glsl/optimize.h +++ b/source/glsl/optimize.h @@ -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 dependencies; + +public: + const std::set &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 inlineable; + FunctionDeclaration *current_function; unsigned extract_result; RefPtr inline_result; + bool any_inlined; public: FunctionInliner(); - void apply(Stage &); + bool apply(Stage &); private: void visit_and_inline(RefPtr &); @@ -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 &); }; diff --git a/source/glsl/visitor.cpp b/source/glsl/visitor.cpp index d8b18139..9bbd4914 100644 --- a/source/glsl/visitor.cpp +++ b/source/glsl/visitor.cpp @@ -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 &tr) +{ + reorder_before = &before; + to_reorder = &tr; + stage.content.visit(*this); +} + +void NodeReorderer::visit(Block &block) +{ + NodeList::iterator insert_point = block.body.end(); + for(NodeList::iterator i=block.body.begin(); i!=block.body.end(); ) + { + (*i)->visit(*this); + if(insert_point!=block.body.end() && to_reorder->count(i->get())) + { + NodeList::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 diff --git a/source/glsl/visitor.h b/source/glsl/visitor.h index 83b310f6..e0d74f62 100644 --- a/source/glsl/visitor.h +++ b/source/glsl/visitor.h @@ -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 *to_reorder; + +public: + NodeReorderer(); + + void apply(Stage &, Node &, const std::set &); + +private: + virtual void visit(Block &); +}; + } // namespace SL } // namespace GL } // namespace Msp -- 2.43.0