From 9ce1ca23401a67c31762687296af0eea28ed3da8 Mon Sep 17 00:00:00 2001 From: chriseth Date: Mon, 23 Sep 2019 16:32:50 +0200 Subject: [PATCH] Refactor Optimiser Steps Interface. --- libyul/CMakeLists.txt | 1 + libyul/backends/wasm/EVMToEWasmTranslator.cpp | 12 +- libyul/optimiser/BlockFlattener.h | 7 + .../CommonSubexpressionEliminator.cpp | 6 +- .../optimiser/CommonSubexpressionEliminator.h | 5 +- libyul/optimiser/ControlFlowSimplifier.cpp | 6 + libyul/optimiser/ControlFlowSimplifier.h | 7 +- libyul/optimiser/DeadCodeEliminator.cpp | 6 + libyul/optimiser/DeadCodeEliminator.h | 6 +- .../optimiser/EquivalentFunctionCombiner.cpp | 2 +- libyul/optimiser/EquivalentFunctionCombiner.h | 6 +- libyul/optimiser/ExpressionInliner.cpp | 10 +- libyul/optimiser/ExpressionInliner.h | 21 +- libyul/optimiser/ExpressionJoiner.cpp | 11 +- libyul/optimiser/ExpressionJoiner.h | 4 +- libyul/optimiser/ExpressionSimplifier.cpp | 12 +- libyul/optimiser/ExpressionSimplifier.h | 5 +- libyul/optimiser/ExpressionSplitter.cpp | 6 + libyul/optimiser/ExpressionSplitter.h | 11 +- libyul/optimiser/ForLoopConditionIntoBody.cpp | 6 + libyul/optimiser/ForLoopConditionIntoBody.h | 8 +- .../optimiser/ForLoopConditionOutOfBody.cpp | 5 + libyul/optimiser/ForLoopConditionOutOfBody.h | 11 +- libyul/optimiser/ForLoopInitRewriter.h | 10 + libyul/optimiser/FullInliner.cpp | 5 + libyul/optimiser/FullInliner.h | 9 +- libyul/optimiser/FunctionGrouper.h | 7 + libyul/optimiser/FunctionHoister.h | 6 + libyul/optimiser/LoadResolver.cpp | 8 +- libyul/optimiser/LoadResolver.h | 4 +- libyul/optimiser/MainFunction.h | 8 + libyul/optimiser/OptimiserStep.h | 65 ++++ .../optimiser/RedundantAssignEliminator.cpp | 17 +- libyul/optimiser/RedundantAssignEliminator.h | 6 +- libyul/optimiser/Rematerialiser.h | 20 +- libyul/optimiser/SSAReverser.cpp | 2 +- libyul/optimiser/SSAReverser.h | 8 +- libyul/optimiser/SSATransform.cpp | 6 +- libyul/optimiser/SSATransform.h | 4 +- libyul/optimiser/StructuralSimplifier.cpp | 5 + libyul/optimiser/StructuralSimplifier.h | 6 + libyul/optimiser/Suite.cpp | 284 ++++++++++++------ libyul/optimiser/Suite.h | 29 ++ libyul/optimiser/UnusedPruner.h | 42 ++- libyul/optimiser/VarDeclInitializer.h | 4 + libyul/optimiser/VarNameCleaner.h | 17 +- test/libyul/YulOptimizerTest.cpp | 151 +++++----- test/libyul/YulOptimizerTest.h | 13 + test/tools/yulopti.cpp | 57 ++-- 49 files changed, 674 insertions(+), 293 deletions(-) create mode 100644 libyul/optimiser/OptimiserStep.h diff --git a/libyul/CMakeLists.txt b/libyul/CMakeLists.txt index c0e173246..0bffc5389 100644 --- a/libyul/CMakeLists.txt +++ b/libyul/CMakeLists.txt @@ -114,6 +114,7 @@ add_library(yul optimiser/NameDispenser.h optimiser/NameDisplacer.cpp optimiser/NameDisplacer.h + optimiser/OptimiserStep.h optimiser/OptimizerUtilities.cpp optimiser/OptimizerUtilities.h optimiser/RedundantAssignEliminator.cpp diff --git a/libyul/backends/wasm/EVMToEWasmTranslator.cpp b/libyul/backends/wasm/EVMToEWasmTranslator.cpp index 75cbe242a..1be9a1a38 100644 --- a/libyul/backends/wasm/EVMToEWasmTranslator.cpp +++ b/libyul/backends/wasm/EVMToEWasmTranslator.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -637,11 +638,14 @@ Object EVMToEWasmTranslator::run(Object const& _object) parsePolyfill(); Block ast = boost::get(Disambiguator(m_dialect, *_object.analysisInfo)(*_object.code)); - NameDispenser nameDispenser{m_dialect, ast}; - FunctionHoister{}(ast); - FunctionGrouper{}(ast); + set reservedIdentifiers; + NameDispenser nameDispenser{m_dialect, ast, reservedIdentifiers}; + OptimiserStepContext context{m_dialect, nameDispenser, reservedIdentifiers}; + + FunctionHoister::run(context, ast); + FunctionGrouper::run(context, ast); MainFunction{}(ast); - ExpressionSplitter{m_dialect, nameDispenser}(ast); + ExpressionSplitter::run(context, ast); WordSizeTransform::run(m_dialect, ast, nameDispenser); NameDisplacer{nameDispenser, m_polyfillFunctions}(ast); diff --git a/libyul/optimiser/BlockFlattener.h b/libyul/optimiser/BlockFlattener.h index b732422d7..5895712e5 100644 --- a/libyul/optimiser/BlockFlattener.h +++ b/libyul/optimiser/BlockFlattener.h @@ -17,6 +17,7 @@ #pragma once #include +#include namespace yul { @@ -24,8 +25,14 @@ namespace yul class BlockFlattener: public ASTModifier { public: + static constexpr char const* name{"BlockFlattener"}; + static void run(OptimiserStepContext&, Block& _ast) { BlockFlattener{}(_ast); } + using ASTModifier::operator(); void operator()(Block& _block) override; + +private: + BlockFlattener() = default; }; } diff --git a/libyul/optimiser/CommonSubexpressionEliminator.cpp b/libyul/optimiser/CommonSubexpressionEliminator.cpp index dded41ba8..65e0bae02 100644 --- a/libyul/optimiser/CommonSubexpressionEliminator.cpp +++ b/libyul/optimiser/CommonSubexpressionEliminator.cpp @@ -34,11 +34,11 @@ using namespace std; using namespace dev; using namespace yul; -void CommonSubexpressionEliminator::run(Dialect const& _dialect, Block& _ast) +void CommonSubexpressionEliminator::run(OptimiserStepContext& _context, Block& _ast) { CommonSubexpressionEliminator cse{ - _dialect, - SideEffectsPropagator::sideEffects(_dialect, CallGraphGenerator::callGraph(_ast)) + _context.dialect, + SideEffectsPropagator::sideEffects(_context.dialect, CallGraphGenerator::callGraph(_ast)) }; cse(_ast); } diff --git a/libyul/optimiser/CommonSubexpressionEliminator.h b/libyul/optimiser/CommonSubexpressionEliminator.h index 07bd47fcc..8db5e7aed 100644 --- a/libyul/optimiser/CommonSubexpressionEliminator.h +++ b/libyul/optimiser/CommonSubexpressionEliminator.h @@ -22,6 +22,7 @@ #pragma once #include +#include namespace yul { @@ -38,8 +39,8 @@ struct SideEffects; class CommonSubexpressionEliminator: public DataFlowAnalyzer { public: - /// Runs the CSE pass. @a _ast needs to be the complete AST of the program! - static void run(Dialect const& _dialect, Block& _ast); + static constexpr char const* name{"CommonSubexpressionEliminator"}; + static void run(OptimiserStepContext&, Block& _ast); private: CommonSubexpressionEliminator( diff --git a/libyul/optimiser/ControlFlowSimplifier.cpp b/libyul/optimiser/ControlFlowSimplifier.cpp index 7c826aa28..96e399027 100644 --- a/libyul/optimiser/ControlFlowSimplifier.cpp +++ b/libyul/optimiser/ControlFlowSimplifier.cpp @@ -16,6 +16,7 @@ */ #include #include +#include #include #include #include @@ -125,6 +126,11 @@ OptionalStatements reduceSingleCaseSwitch(Dialect const& _dialect, Switch& _swit } +void ControlFlowSimplifier::run(OptimiserStepContext& _context, Block& _ast) +{ + ControlFlowSimplifier{_context.dialect}(_ast); +} + void ControlFlowSimplifier::operator()(Block& _block) { simplify(_block.statements); diff --git a/libyul/optimiser/ControlFlowSimplifier.h b/libyul/optimiser/ControlFlowSimplifier.h index 23dc3075b..1f1c287ec 100644 --- a/libyul/optimiser/ControlFlowSimplifier.h +++ b/libyul/optimiser/ControlFlowSimplifier.h @@ -17,10 +17,12 @@ #pragma once #include +#include namespace yul { struct Dialect; +struct OptimiserStepContext; /** * Simplifies several control-flow structures: @@ -46,7 +48,8 @@ struct Dialect; class ControlFlowSimplifier: public ASTModifier { public: - ControlFlowSimplifier(Dialect const& _dialect): m_dialect(_dialect) {} + static constexpr char const* name{"ControlFlowSimplifier"}; + static void run(OptimiserStepContext&, Block& _ast); using ASTModifier::operator(); void operator()(Break&) override { ++m_numBreakStatements; } @@ -56,6 +59,8 @@ public: void visit(Statement& _st) override; private: + ControlFlowSimplifier(Dialect const& _dialect): m_dialect(_dialect) {} + void simplify(std::vector& _statements); Dialect const& m_dialect; diff --git a/libyul/optimiser/DeadCodeEliminator.cpp b/libyul/optimiser/DeadCodeEliminator.cpp index 5d123ca74..95e1cf284 100644 --- a/libyul/optimiser/DeadCodeEliminator.cpp +++ b/libyul/optimiser/DeadCodeEliminator.cpp @@ -20,6 +20,7 @@ #include #include +#include #include #include @@ -32,6 +33,11 @@ using namespace dev; using namespace yul; +void DeadCodeEliminator::run(OptimiserStepContext& _context, Block& _ast) +{ + DeadCodeEliminator{_context.dialect}(_ast); +} + void DeadCodeEliminator::operator()(ForLoop& _for) { yulAssert(_for.pre.statements.empty(), "DeadCodeEliminator needs ForLoopInitRewriter as a prerequisite."); diff --git a/libyul/optimiser/DeadCodeEliminator.h b/libyul/optimiser/DeadCodeEliminator.h index 50dbaaa75..f0fe9c647 100644 --- a/libyul/optimiser/DeadCodeEliminator.h +++ b/libyul/optimiser/DeadCodeEliminator.h @@ -29,6 +29,7 @@ namespace yul { struct Dialect; +struct OptimiserStepContext; /** * Optimisation stage that removes unreachable code @@ -47,13 +48,16 @@ struct Dialect; class DeadCodeEliminator: public ASTModifier { public: - DeadCodeEliminator(Dialect const& _dialect): m_dialect(_dialect) {} + static constexpr char const* name{"DeadCodeEliminator"}; + static void run(OptimiserStepContext&, Block& _ast); using ASTModifier::operator(); void operator()(ForLoop& _for) override; void operator()(Block& _block) override; private: + DeadCodeEliminator(Dialect const& _dialect): m_dialect(_dialect) {} + Dialect const& m_dialect; }; diff --git a/libyul/optimiser/EquivalentFunctionCombiner.cpp b/libyul/optimiser/EquivalentFunctionCombiner.cpp index c9b34436b..d7b3e62a6 100644 --- a/libyul/optimiser/EquivalentFunctionCombiner.cpp +++ b/libyul/optimiser/EquivalentFunctionCombiner.cpp @@ -26,7 +26,7 @@ using namespace std; using namespace dev; using namespace yul; -void EquivalentFunctionCombiner::run(Block& _ast) +void EquivalentFunctionCombiner::run(OptimiserStepContext&, Block& _ast) { EquivalentFunctionCombiner{EquivalentFunctionDetector::run(_ast)}(_ast); } diff --git a/libyul/optimiser/EquivalentFunctionCombiner.h b/libyul/optimiser/EquivalentFunctionCombiner.h index 0c766ded4..0d120d679 100644 --- a/libyul/optimiser/EquivalentFunctionCombiner.h +++ b/libyul/optimiser/EquivalentFunctionCombiner.h @@ -21,11 +21,14 @@ #include #include +#include #include namespace yul { +struct OptimiserStepContext; + /** * Optimiser component that detects syntactically equivalent functions and replaces all calls to any of them by calls * to one particular of them. @@ -35,7 +38,8 @@ namespace yul class EquivalentFunctionCombiner: public ASTModifier { public: - static void run(Block& _ast); + static constexpr char const* name{"EquivalentFunctionCombiner"}; + static void run(OptimiserStepContext&, Block& _ast); using ASTModifier::operator(); void operator()(FunctionCall& _funCall) override; diff --git a/libyul/optimiser/ExpressionInliner.cpp b/libyul/optimiser/ExpressionInliner.cpp index a4ce64e4a..5b1064cc8 100644 --- a/libyul/optimiser/ExpressionInliner.cpp +++ b/libyul/optimiser/ExpressionInliner.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include @@ -32,13 +33,12 @@ using namespace std; using namespace dev; using namespace yul; -void ExpressionInliner::run() +void ExpressionInliner::run(OptimiserStepContext& _context, Block& _ast) { InlinableExpressionFunctionFinder funFinder; - funFinder(m_block); - m_inlinableFunctions = funFinder.inlinableFunctions(); - - (*this)(m_block); + funFinder(_ast); + ExpressionInliner inliner{_context.dialect, funFinder.inlinableFunctions()}; + inliner(_ast); } void ExpressionInliner::operator()(FunctionDefinition& _fun) diff --git a/libyul/optimiser/ExpressionInliner.h b/libyul/optimiser/ExpressionInliner.h index 6101bac83..16e48ceb5 100644 --- a/libyul/optimiser/ExpressionInliner.h +++ b/libyul/optimiser/ExpressionInliner.h @@ -30,6 +30,7 @@ namespace yul { struct Dialect; +struct OptimiserStepContext; /** * Optimiser component that modifies an AST in place, inlining functions that can be @@ -48,11 +49,8 @@ struct Dialect; class ExpressionInliner: public ASTModifier { public: - ExpressionInliner(Dialect const& _dialect, Block& _block): - m_block(_block), m_dialect(_dialect) - {} - - void run(); + static constexpr char const* name{"ExpressionInliner"}; + static void run(OptimiserStepContext&, Block& _ast); using ASTModifier::operator(); void operator()(FunctionDefinition& _fun) override; @@ -60,13 +58,18 @@ public: void visit(Expression& _expression) override; private: - std::map m_inlinableFunctions; + ExpressionInliner( + Dialect const& _dialect, + std::map const& _inlinableFunctions + ): m_dialect(_dialect), m_inlinableFunctions(_inlinableFunctions) + {} + + Dialect const& m_dialect; + std::map const& m_inlinableFunctions; + std::map m_varReplacements; /// Set of functions we are currently visiting inside. std::set m_currentFunctions; - - Block& m_block; - Dialect const& m_dialect; }; } diff --git a/libyul/optimiser/ExpressionJoiner.cpp b/libyul/optimiser/ExpressionJoiner.cpp index 654e9b5a8..911d44de0 100644 --- a/libyul/optimiser/ExpressionJoiner.cpp +++ b/libyul/optimiser/ExpressionJoiner.cpp @@ -34,6 +34,12 @@ using namespace std; using namespace dev; using namespace yul; +void ExpressionJoiner::run(OptimiserStepContext&, Block& _ast) +{ + ExpressionJoiner{_ast}(_ast); +} + + void ExpressionJoiner::operator()(FunctionalInstruction& _instruction) { handleArguments(_instruction.arguments); @@ -78,11 +84,6 @@ void ExpressionJoiner::visit(Expression& _e) ASTModifier::visit(_e); } -void ExpressionJoiner::run(Block& _ast) -{ - ExpressionJoiner{_ast}(_ast); -} - ExpressionJoiner::ExpressionJoiner(Block& _ast) { m_references = ReferencesCounter::countReferences(_ast); diff --git a/libyul/optimiser/ExpressionJoiner.h b/libyul/optimiser/ExpressionJoiner.h index 643d62b0a..e3b496b7c 100644 --- a/libyul/optimiser/ExpressionJoiner.h +++ b/libyul/optimiser/ExpressionJoiner.h @@ -29,6 +29,7 @@ namespace yul { class NameCollector; +struct OptimiserStepContext; /** @@ -70,7 +71,8 @@ class NameCollector; class ExpressionJoiner: public ASTModifier { public: - static void run(Block& _ast); + static constexpr char const* name{"ExpressionJoiner"}; + static void run(OptimiserStepContext&, Block& _ast); private: explicit ExpressionJoiner(Block& _ast); diff --git a/libyul/optimiser/ExpressionSimplifier.cpp b/libyul/optimiser/ExpressionSimplifier.cpp index defe3598a..ce896e649 100644 --- a/libyul/optimiser/ExpressionSimplifier.cpp +++ b/libyul/optimiser/ExpressionSimplifier.cpp @@ -22,7 +22,7 @@ #include #include -#include +#include #include #include @@ -31,6 +31,11 @@ using namespace std; using namespace dev; using namespace yul; +void ExpressionSimplifier::run(OptimiserStepContext& _context, Block& _ast) +{ + ExpressionSimplifier{_context.dialect}(_ast); +} + void ExpressionSimplifier::visit(Expression& _expression) { ASTModifier::visit(_expression); @@ -48,8 +53,3 @@ void ExpressionSimplifier::visit(Expression& _expression) _expression = match->action().toExpression(locationOf(_expression)); } } - -void ExpressionSimplifier::run(Dialect const& _dialect, Block& _ast) -{ - ExpressionSimplifier{_dialect}(_ast); -} diff --git a/libyul/optimiser/ExpressionSimplifier.h b/libyul/optimiser/ExpressionSimplifier.h index 1f371a8fc..a7dbb3b41 100644 --- a/libyul/optimiser/ExpressionSimplifier.h +++ b/libyul/optimiser/ExpressionSimplifier.h @@ -27,6 +27,7 @@ namespace yul { struct Dialect; +struct OptimiserStepContext; /** * Applies simplification rules to all expressions. @@ -41,10 +42,12 @@ struct Dialect; class ExpressionSimplifier: public DataFlowAnalyzer { public: + static constexpr char const* name{"ExpressionSimplifier"}; + static void run(OptimiserStepContext&, Block& _ast); + using ASTModifier::operator(); virtual void visit(Expression& _expression); - static void run(Dialect const& _dialect, Block& _ast); private: explicit ExpressionSimplifier(Dialect const& _dialect): DataFlowAnalyzer(_dialect) {} }; diff --git a/libyul/optimiser/ExpressionSplitter.cpp b/libyul/optimiser/ExpressionSplitter.cpp index 7eb099b8e..4c857f0a3 100644 --- a/libyul/optimiser/ExpressionSplitter.cpp +++ b/libyul/optimiser/ExpressionSplitter.cpp @@ -22,6 +22,7 @@ #include #include +#include #include #include @@ -35,6 +36,11 @@ using namespace dev; using namespace langutil; using namespace yul; +void ExpressionSplitter::run(OptimiserStepContext& _context, Block& _ast) +{ + ExpressionSplitter{_context.dialect, _context.dispenser}(_ast); +} + void ExpressionSplitter::operator()(FunctionalInstruction& _instruction) { for (auto& arg: _instruction.arguments | boost::adaptors::reversed) diff --git a/libyul/optimiser/ExpressionSplitter.h b/libyul/optimiser/ExpressionSplitter.h index a72d14ba4..7a2a97464 100644 --- a/libyul/optimiser/ExpressionSplitter.h +++ b/libyul/optimiser/ExpressionSplitter.h @@ -32,7 +32,7 @@ namespace yul class NameCollector; struct Dialect; - +struct OptimiserStepContext; /** * Optimiser component that modifies an AST in place, turning complex @@ -58,9 +58,8 @@ struct Dialect; class ExpressionSplitter: public ASTModifier { public: - explicit ExpressionSplitter(Dialect const& _dialect, NameDispenser& _nameDispenser): - m_dialect(_dialect), m_nameDispenser(_nameDispenser) - { } + static constexpr char const* name{"ExpressionSplitter"}; + static void run(OptimiserStepContext&, Block& _ast); void operator()(FunctionalInstruction&) override; void operator()(FunctionCall&) override; @@ -70,6 +69,10 @@ public: void operator()(Block& _block) override; private: + explicit ExpressionSplitter(Dialect const& _dialect, NameDispenser& _nameDispenser): + m_dialect(_dialect), m_nameDispenser(_nameDispenser) + { } + /// Replaces the expression by a variable if it is a function call or functional /// instruction. The declaration of the variable is appended to m_statementsToPrefix. /// Recurses via visit(). diff --git a/libyul/optimiser/ForLoopConditionIntoBody.cpp b/libyul/optimiser/ForLoopConditionIntoBody.cpp index 919b194f1..ca53b8d6c 100644 --- a/libyul/optimiser/ForLoopConditionIntoBody.cpp +++ b/libyul/optimiser/ForLoopConditionIntoBody.cpp @@ -16,6 +16,7 @@ */ #include +#include #include #include @@ -23,6 +24,11 @@ using namespace std; using namespace dev; using namespace yul; +void ForLoopConditionIntoBody::run(OptimiserStepContext& _context, Block& _ast) +{ + ForLoopConditionIntoBody{_context.dialect}(_ast); +} + void ForLoopConditionIntoBody::operator()(ForLoop& _forLoop) { if (m_dialect.booleanNegationFunction() && _forLoop.condition->type() != typeid(Literal)) diff --git a/libyul/optimiser/ForLoopConditionIntoBody.h b/libyul/optimiser/ForLoopConditionIntoBody.h index 508511758..e15c502c8 100644 --- a/libyul/optimiser/ForLoopConditionIntoBody.h +++ b/libyul/optimiser/ForLoopConditionIntoBody.h @@ -22,6 +22,8 @@ namespace yul { +struct OptimiserStepContext; + /** * Rewrites ForLoop by moving iteration condition into the ForLoop body. * For example, `for {} lt(a, b) {} { mstore(1, 2) }` will become @@ -40,11 +42,15 @@ namespace yul class ForLoopConditionIntoBody: public ASTModifier { public: - ForLoopConditionIntoBody(Dialect const& _dialect): m_dialect(_dialect) {} + static constexpr char const* name{"ForLoopConditionIntoBody"}; + static void run(OptimiserStepContext&, Block& _ast); + using ASTModifier::operator(); void operator()(ForLoop& _forLoop) override; private: + ForLoopConditionIntoBody(Dialect const& _dialect): m_dialect(_dialect) {} + Dialect const& m_dialect; }; diff --git a/libyul/optimiser/ForLoopConditionOutOfBody.cpp b/libyul/optimiser/ForLoopConditionOutOfBody.cpp index d0cc3a441..e3d0f13ff 100644 --- a/libyul/optimiser/ForLoopConditionOutOfBody.cpp +++ b/libyul/optimiser/ForLoopConditionOutOfBody.cpp @@ -25,6 +25,11 @@ using namespace std; using namespace dev; using namespace yul; +void ForLoopConditionOutOfBody::run(OptimiserStepContext& _context, Block& _ast) +{ + ForLoopConditionOutOfBody{_context.dialect}(_ast); +} + void ForLoopConditionOutOfBody::operator()(ForLoop& _forLoop) { ASTModifier::operator()(_forLoop); diff --git a/libyul/optimiser/ForLoopConditionOutOfBody.h b/libyul/optimiser/ForLoopConditionOutOfBody.h index baa4c62d4..8945bf752 100644 --- a/libyul/optimiser/ForLoopConditionOutOfBody.h +++ b/libyul/optimiser/ForLoopConditionOutOfBody.h @@ -17,6 +17,7 @@ #pragma once #include +#include #include namespace yul @@ -56,13 +57,17 @@ namespace yul class ForLoopConditionOutOfBody: public ASTModifier { public: - ForLoopConditionOutOfBody(Dialect const& _dialect): - m_dialect(_dialect) - {} + static constexpr char const* name{"ForLoopConditionOutOfBody"}; + static void run(OptimiserStepContext&, Block& _ast); + using ASTModifier::operator(); void operator()(ForLoop& _forLoop) override; private: + ForLoopConditionOutOfBody(Dialect const& _dialect): + m_dialect(_dialect) + {} + Dialect const& m_dialect; }; diff --git a/libyul/optimiser/ForLoopInitRewriter.h b/libyul/optimiser/ForLoopInitRewriter.h index e925c6c2e..a36f76fdd 100644 --- a/libyul/optimiser/ForLoopInitRewriter.h +++ b/libyul/optimiser/ForLoopInitRewriter.h @@ -17,6 +17,7 @@ #pragma once #include +#include namespace yul { @@ -29,8 +30,17 @@ namespace yul class ForLoopInitRewriter: public ASTModifier { public: + static constexpr char const* name{"ForLoopInitRewriter"}; + static void run(OptimiserStepContext&, Block& _ast) + { + ForLoopInitRewriter{}(_ast); + } + using ASTModifier::operator(); void operator()(Block& _block) override; + +private: + ForLoopInitRewriter() = default; }; } diff --git a/libyul/optimiser/FullInliner.cpp b/libyul/optimiser/FullInliner.cpp index f764b0b1e..437758481 100644 --- a/libyul/optimiser/FullInliner.cpp +++ b/libyul/optimiser/FullInliner.cpp @@ -38,6 +38,11 @@ using namespace std; using namespace dev; using namespace yul; +void FullInliner::run(OptimiserStepContext& _context, Block& _ast) +{ + FullInliner{_ast, _context.dispenser}.run(); +} + FullInliner::FullInliner(Block& _ast, NameDispenser& _dispenser): m_ast(_ast), m_nameDispenser(_dispenser) { diff --git a/libyul/optimiser/FullInliner.h b/libyul/optimiser/FullInliner.h index 43ecddbfc..4f1ea9d3c 100644 --- a/libyul/optimiser/FullInliner.h +++ b/libyul/optimiser/FullInliner.h @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -69,9 +70,8 @@ class NameCollector; class FullInliner: public ASTModifier { public: - explicit FullInliner(Block& _ast, NameDispenser& _dispenser); - - void run(); + static constexpr char const* name{"FullInliner"}; + static void run(OptimiserStepContext&, Block& _ast); /// Inlining heuristic. /// @param _callSite the name of the function in which the function call is located. @@ -91,6 +91,9 @@ public: void tentativelyUpdateCodeSize(YulString _function, YulString _callSite); private: + FullInliner(Block& _ast, NameDispenser& _dispenser); + void run(); + void updateCodeSize(FunctionDefinition const& _fun); void handleBlock(YulString _currentFunctionName, Block& _block); bool recursive(FunctionDefinition const& _fun) const; diff --git a/libyul/optimiser/FunctionGrouper.h b/libyul/optimiser/FunctionGrouper.h index 4b6abf761..2e36c1be6 100644 --- a/libyul/optimiser/FunctionGrouper.h +++ b/libyul/optimiser/FunctionGrouper.h @@ -26,6 +26,8 @@ namespace yul { +struct OptimiserStepContext; + /** * Moves all instructions in a block into a new block at the start of the block, followed by * all function definitions. @@ -37,9 +39,14 @@ namespace yul class FunctionGrouper { public: + static constexpr char const* name{"FunctionGrouper"}; + static void run(OptimiserStepContext&, Block& _ast) { FunctionGrouper{}(_ast); } + void operator()(Block& _block); private: + FunctionGrouper() = default; + bool alreadyGrouped(Block const& _block); }; diff --git a/libyul/optimiser/FunctionHoister.h b/libyul/optimiser/FunctionHoister.h index 310920696..4807d7625 100644 --- a/libyul/optimiser/FunctionHoister.h +++ b/libyul/optimiser/FunctionHoister.h @@ -26,6 +26,7 @@ namespace yul { +struct OptimiserStepContext; /** * Moves all functions to the top-level scope. @@ -37,10 +38,15 @@ namespace yul class FunctionHoister: public ASTModifier { public: + static constexpr char const* name{"FunctionHoister"}; + static void run(OptimiserStepContext&, Block& _ast) { FunctionHoister{}(_ast); } + using ASTModifier::operator(); virtual void operator()(Block& _block); private: + FunctionHoister() = default; + bool m_isTopLevel = true; std::vector m_functions; }; diff --git a/libyul/optimiser/LoadResolver.cpp b/libyul/optimiser/LoadResolver.cpp index 3ff064fd7..184214254 100644 --- a/libyul/optimiser/LoadResolver.cpp +++ b/libyul/optimiser/LoadResolver.cpp @@ -31,12 +31,12 @@ using namespace std; using namespace dev; using namespace yul; -void LoadResolver::run(Dialect const& _dialect, Block& _ast) +void LoadResolver::run(OptimiserStepContext& _context, Block& _ast) { - bool containsMSize = MSizeFinder::containsMSize(_dialect, _ast); + bool containsMSize = MSizeFinder::containsMSize(_context.dialect, _ast); LoadResolver{ - _dialect, - SideEffectsPropagator::sideEffects(_dialect, CallGraphGenerator::callGraph(_ast)), + _context.dialect, + SideEffectsPropagator::sideEffects(_context.dialect, CallGraphGenerator::callGraph(_ast)), !containsMSize }(_ast); } diff --git a/libyul/optimiser/LoadResolver.h b/libyul/optimiser/LoadResolver.h index 37afc6b6e..52ac935dd 100644 --- a/libyul/optimiser/LoadResolver.h +++ b/libyul/optimiser/LoadResolver.h @@ -22,6 +22,7 @@ #pragma once #include +#include #include namespace yul @@ -41,8 +42,9 @@ struct BuiltinFunctionForEVM; class LoadResolver: public DataFlowAnalyzer { public: + static constexpr char const* name{"LoadResolver"}; /// Run the load resolver on the given complete AST. - static void run(Dialect const& _dialect, Block& _ast); + static void run(OptimiserStepContext&, Block& _ast); private: LoadResolver( diff --git a/libyul/optimiser/MainFunction.h b/libyul/optimiser/MainFunction.h index 96acc0ac8..03e94a51f 100644 --- a/libyul/optimiser/MainFunction.h +++ b/libyul/optimiser/MainFunction.h @@ -26,13 +26,21 @@ namespace yul { +struct OptimiserStepContext; + /** * Prerequisites: Function Grouper */ class MainFunction { public: + static constexpr char const* name{"MainFunction"}; + static void run(OptimiserStepContext&, Block& _ast) { MainFunction{}(_ast); } + void operator()(Block& _block); + +private: + MainFunction() = default; }; } diff --git a/libyul/optimiser/OptimiserStep.h b/libyul/optimiser/OptimiserStep.h new file mode 100644 index 000000000..485a7b422 --- /dev/null +++ b/libyul/optimiser/OptimiserStep.h @@ -0,0 +1,65 @@ +/* + This file is part of solidity. + + solidity is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + solidity is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with solidity. If not, see . +*/ + +#pragma once + +#include + +#include +#include + +namespace yul +{ + +struct Dialect; +struct Block; +class YulString; +class NameDispenser; + +struct OptimiserStepContext +{ + Dialect const& dialect; + NameDispenser& dispenser; + std::set const& reservedIdentifiers; +}; + + +/** + * Construction to create dynamically callable objects out of the + * statically callable optimiser steps. + */ +struct OptimiserStep +{ + explicit OptimiserStep(std::string _name): name(std::move(_name)) {} + virtual ~OptimiserStep() = default; + + virtual void run(OptimiserStepContext&, Block&) const = 0; + std::string name; +}; + +template +struct OptimiserStepInstance: public OptimiserStep +{ + OptimiserStepInstance(): OptimiserStep{Step::name} {} + void run(OptimiserStepContext& _context, Block& _ast) const override + { + Step::run(_context, _ast); + } +}; + + +} diff --git a/libyul/optimiser/RedundantAssignEliminator.cpp b/libyul/optimiser/RedundantAssignEliminator.cpp index 8baa4e7dc..16383d307 100644 --- a/libyul/optimiser/RedundantAssignEliminator.cpp +++ b/libyul/optimiser/RedundantAssignEliminator.cpp @@ -32,6 +32,15 @@ using namespace std; using namespace dev; using namespace yul; +void RedundantAssignEliminator::run(OptimiserStepContext& _context, Block& _ast) +{ + RedundantAssignEliminator rae{_context.dialect}; + rae(_ast); + + AssignmentRemover remover{rae.m_pendingRemovals}; + remover(_ast); +} + void RedundantAssignEliminator::operator()(Identifier const& _identifier) { changeUndecidedTo(_identifier.name, State::Used); @@ -204,14 +213,6 @@ void RedundantAssignEliminator::operator()(Block const& _block) swap(m_declaredVariables, outerDeclaredVariables); } -void RedundantAssignEliminator::run(Dialect const& _dialect, Block& _ast) -{ - RedundantAssignEliminator rae{_dialect}; - rae(_ast); - - AssignmentRemover remover{rae.m_pendingRemovals}; - remover(_ast); -} template void joinMap(std::map& _a, std::map&& _b, F _conflictSolver) diff --git a/libyul/optimiser/RedundantAssignEliminator.h b/libyul/optimiser/RedundantAssignEliminator.h index ecea0fefa..65ddc19ae 100644 --- a/libyul/optimiser/RedundantAssignEliminator.h +++ b/libyul/optimiser/RedundantAssignEliminator.h @@ -23,6 +23,7 @@ #include #include +#include #include #include @@ -105,6 +106,9 @@ struct Dialect; class RedundantAssignEliminator: public ASTWalker { public: + static constexpr char const* name{"RedundantAssignEliminator"}; + static void run(OptimiserStepContext&, Block& _ast); + explicit RedundantAssignEliminator(Dialect const& _dialect): m_dialect(&_dialect) {} RedundantAssignEliminator() = delete; RedundantAssignEliminator(RedundantAssignEliminator const&) = delete; @@ -123,8 +127,6 @@ public: void operator()(Continue const&) override; void operator()(Block const& _block) override; - static void run(Dialect const& _dialect, Block& _ast); - private: class State { diff --git a/libyul/optimiser/Rematerialiser.h b/libyul/optimiser/Rematerialiser.h index 339a6a38f..acf48d669 100644 --- a/libyul/optimiser/Rematerialiser.h +++ b/libyul/optimiser/Rematerialiser.h @@ -21,6 +21,7 @@ #pragma once #include +#include namespace yul { @@ -38,6 +39,12 @@ namespace yul class Rematerialiser: public DataFlowAnalyzer { public: + static constexpr char const* name{"Rematerialiser"}; + static void run( + OptimiserStepContext& _context, + Block& _ast + ) { run(_context.dialect, _ast); } + static void run( Dialect const& _dialect, Block& _ast, @@ -80,12 +87,19 @@ protected: class LiteralRematerialiser: public DataFlowAnalyzer { public: - LiteralRematerialiser(Dialect const& _dialect): - DataFlowAnalyzer(_dialect) - {} + static constexpr char const* name{"LiteralRematerialiser"}; + static void run( + OptimiserStepContext& _context, + Block& _ast + ) { LiteralRematerialiser{_context.dialect}(_ast); } using ASTModifier::visit; void visit(Expression& _e) override; + +private: + LiteralRematerialiser(Dialect const& _dialect): + DataFlowAnalyzer(_dialect) + {} }; diff --git a/libyul/optimiser/SSAReverser.cpp b/libyul/optimiser/SSAReverser.cpp index 5bc6ab5c6..d5f989d18 100644 --- a/libyul/optimiser/SSAReverser.cpp +++ b/libyul/optimiser/SSAReverser.cpp @@ -23,7 +23,7 @@ using namespace std; using namespace dev; using namespace yul; -void SSAReverser::run(Block& _block) +void SSAReverser::run(OptimiserStepContext&, Block& _block) { AssignmentCounter assignmentCounter; assignmentCounter(_block); diff --git a/libyul/optimiser/SSAReverser.h b/libyul/optimiser/SSAReverser.h index 7845bff5d..a0425a9ea 100644 --- a/libyul/optimiser/SSAReverser.h +++ b/libyul/optimiser/SSAReverser.h @@ -17,6 +17,7 @@ #pragma once #include +#include namespace yul { @@ -69,12 +70,15 @@ class AssignmentCounter; class SSAReverser: public ASTModifier { public: + static constexpr char const* name{"SSAReverser"}; + static void run(OptimiserStepContext& _context, Block& _ast); + using ASTModifier::operator(); void operator()(Block& _block) override; - static void run(Block& _block); private: - SSAReverser(AssignmentCounter const& _assignmentCounter): m_assignmentCounter(_assignmentCounter) {} + explicit SSAReverser(AssignmentCounter const& _assignmentCounter): m_assignmentCounter(_assignmentCounter) {} + AssignmentCounter const& m_assignmentCounter; }; diff --git a/libyul/optimiser/SSATransform.cpp b/libyul/optimiser/SSATransform.cpp index eede7d45b..9d9175754 100644 --- a/libyul/optimiser/SSATransform.cpp +++ b/libyul/optimiser/SSATransform.cpp @@ -373,12 +373,12 @@ void PropagateValues::operator()(Block& _block) } -void SSATransform::run(Block& _ast, NameDispenser& _nameDispenser) +void SSATransform::run(OptimiserStepContext& _context, Block& _ast) { Assignments assignments; assignments(_ast); - IntroduceSSA{_nameDispenser, assignments.names()}(_ast); - IntroduceControlFlowSSA{_nameDispenser, assignments.names()}(_ast); + IntroduceSSA{_context.dispenser, assignments.names()}(_ast); + IntroduceControlFlowSSA{_context.dispenser, assignments.names()}(_ast); PropagateValues{assignments.names()}(_ast); } diff --git a/libyul/optimiser/SSATransform.h b/libyul/optimiser/SSATransform.h index 949f82a09..938a23151 100644 --- a/libyul/optimiser/SSATransform.h +++ b/libyul/optimiser/SSATransform.h @@ -22,6 +22,7 @@ #include #include +#include #include @@ -89,7 +90,8 @@ class NameDispenser; class SSATransform: public ASTModifier { public: - static void run(Block& _ast, NameDispenser& _nameDispenser); + static constexpr char const* name{"SSATransform"}; + static void run(OptimiserStepContext& _context, Block& _ast); }; } diff --git a/libyul/optimiser/StructuralSimplifier.cpp b/libyul/optimiser/StructuralSimplifier.cpp index b9d941e43..d7bd36fe9 100644 --- a/libyul/optimiser/StructuralSimplifier.cpp +++ b/libyul/optimiser/StructuralSimplifier.cpp @@ -59,6 +59,11 @@ OptionalStatements replaceConstArgSwitch(Switch& _switchStmt, u256 const& _const } +void StructuralSimplifier::run(OptimiserStepContext&, Block& _ast) +{ + StructuralSimplifier{}(_ast); +} + void StructuralSimplifier::operator()(Block& _block) { simplify(_block.statements); diff --git a/libyul/optimiser/StructuralSimplifier.h b/libyul/optimiser/StructuralSimplifier.h index 34a077a6f..28917bff9 100644 --- a/libyul/optimiser/StructuralSimplifier.h +++ b/libyul/optimiser/StructuralSimplifier.h @@ -18,6 +18,7 @@ #include #include +#include #include namespace yul @@ -39,9 +40,14 @@ namespace yul class StructuralSimplifier: public ASTModifier { public: + static constexpr char const* name{"StructuralSimplifier"}; + static void run(OptimiserStepContext&, Block& _ast); + using ASTModifier::operator(); void operator()(Block& _block) override; private: + StructuralSimplifier() = default; + void simplify(std::vector& _statements); bool expressionAlwaysTrue(Expression const& _expression); bool expressionAlwaysFalse(Expression const& _expression); diff --git a/libyul/optimiser/Suite.cpp b/libyul/optimiser/Suite.cpp index 88776a584..a23f1f24e 100644 --- a/libyul/optimiser/Suite.cpp +++ b/libyul/optimiser/Suite.cpp @@ -83,26 +83,28 @@ void OptimiserSuite::run( )(*_object.code)); Block& ast = *_object.code; - VarDeclInitializer{}(ast); - FunctionHoister{}(ast); - BlockFlattener{}(ast); - ForLoopInitRewriter{}(ast); - DeadCodeEliminator{_dialect}(ast); - FunctionGrouper{}(ast); - EquivalentFunctionCombiner::run(ast); - UnusedPruner::runUntilStabilisedOnFullAST(_dialect, ast, reservedIdentifiers); - BlockFlattener{}(ast); - ControlFlowSimplifier{_dialect}(ast); - LiteralRematerialiser{_dialect}(ast); - StructuralSimplifier{}(ast); - ControlFlowSimplifier{_dialect}(ast); - ForLoopConditionIntoBody{_dialect}(ast); - BlockFlattener{}(ast); + OptimiserSuite suite(_dialect, reservedIdentifiers, Debug::None, ast); + + suite.runSequence({ + VarDeclInitializer::name, + FunctionHoister::name, + BlockFlattener::name, + ForLoopInitRewriter::name, + DeadCodeEliminator::name, + FunctionGrouper::name, + EquivalentFunctionCombiner::name, + UnusedPruner::name, + BlockFlattener::name, + ControlFlowSimplifier::name, + LiteralRematerialiser::name, + StructuralSimplifier::name, + ControlFlowSimplifier::name, + ForLoopConditionIntoBody::name, + BlockFlattener::name + }, ast); // None of the above can make stack problems worse. - NameDispenser dispenser{_dialect, ast, reservedIdentifiers}; - size_t codeSize = 0; for (size_t rounds = 0; rounds < 12; ++rounds) { @@ -115,120 +117,138 @@ void OptimiserSuite::run( { // Turn into SSA and simplify - ExpressionSplitter{_dialect, dispenser}(ast); - SSATransform::run(ast, dispenser); - RedundantAssignEliminator::run(_dialect, ast); - RedundantAssignEliminator::run(_dialect, ast); - - ExpressionSimplifier::run(_dialect, ast); - - CommonSubexpressionEliminator::run(_dialect, ast); - LoadResolver::run(_dialect, ast); + suite.runSequence({ + ExpressionSplitter::name, + SSATransform::name, + RedundantAssignEliminator::name, + RedundantAssignEliminator::name, + ExpressionSimplifier::name, + CommonSubexpressionEliminator::name, + LoadResolver::name + }, ast); } { // still in SSA, perform structural simplification - LiteralRematerialiser{_dialect}(ast); - ForLoopConditionOutOfBody{_dialect}(ast); - ControlFlowSimplifier{_dialect}(ast); - StructuralSimplifier{}(ast); - ControlFlowSimplifier{_dialect}(ast); - BlockFlattener{}(ast); - DeadCodeEliminator{_dialect}(ast); - ForLoopConditionIntoBody{_dialect}(ast); - UnusedPruner::runUntilStabilisedOnFullAST(_dialect, ast, reservedIdentifiers); + suite.runSequence({ + LiteralRematerialiser::name, + ForLoopConditionOutOfBody::name, + ControlFlowSimplifier::name, + StructuralSimplifier::name, + ControlFlowSimplifier::name, + BlockFlattener::name, + DeadCodeEliminator::name, + ForLoopConditionIntoBody::name, + UnusedPruner::name + }, ast); } { // simplify again - LoadResolver::run(_dialect, ast); - CommonSubexpressionEliminator::run(_dialect, ast); - UnusedPruner::runUntilStabilisedOnFullAST(_dialect, ast, reservedIdentifiers); + suite.runSequence({ + LoadResolver::name, + CommonSubexpressionEliminator::name, + UnusedPruner::name, + }, ast); } { // reverse SSA - SSAReverser::run(ast); - CommonSubexpressionEliminator::run(_dialect, ast); - UnusedPruner::runUntilStabilisedOnFullAST(_dialect, ast, reservedIdentifiers); + suite.runSequence({ + SSAReverser::name, + CommonSubexpressionEliminator::name, + UnusedPruner::name, - ExpressionJoiner::run(ast); - ExpressionJoiner::run(ast); + ExpressionJoiner::name, + ExpressionJoiner::name, + }, ast); } // should have good "compilability" property here. { // run functional expression inliner - ExpressionInliner(_dialect, ast).run(); - UnusedPruner::runUntilStabilisedOnFullAST(_dialect, ast, reservedIdentifiers); + suite.runSequence({ + ExpressionInliner::name, + UnusedPruner::name, + }, ast); } { // Turn into SSA again and simplify - ExpressionSplitter{_dialect, dispenser}(ast); - SSATransform::run(ast, dispenser); - RedundantAssignEliminator::run(_dialect, ast); - RedundantAssignEliminator::run(_dialect, ast); - CommonSubexpressionEliminator::run(_dialect, ast); - LoadResolver::run(_dialect, ast); + suite.runSequence({ + ExpressionSplitter::name, + SSATransform::name, + RedundantAssignEliminator::name, + RedundantAssignEliminator::name, + CommonSubexpressionEliminator::name, + LoadResolver::name, + }, ast); } { // run full inliner - FunctionGrouper{}(ast); - EquivalentFunctionCombiner::run(ast); - FullInliner{ast, dispenser}.run(); - BlockFlattener{}(ast); + suite.runSequence({ + FunctionGrouper::name, + EquivalentFunctionCombiner::name, + FullInliner::name, + BlockFlattener::name + }, ast); } { // SSA plus simplify - SSATransform::run(ast, dispenser); - RedundantAssignEliminator::run(_dialect, ast); - RedundantAssignEliminator::run(_dialect, ast); - LoadResolver::run(_dialect, ast); - ExpressionSimplifier::run(_dialect, ast); - LiteralRematerialiser{_dialect}(ast); - ForLoopConditionOutOfBody{_dialect}(ast); - StructuralSimplifier{}(ast); - BlockFlattener{}(ast); - DeadCodeEliminator{_dialect}(ast); - ControlFlowSimplifier{_dialect}(ast); - CommonSubexpressionEliminator::run(_dialect, ast); - SSATransform::run(ast, dispenser); - RedundantAssignEliminator::run(_dialect, ast); - RedundantAssignEliminator::run(_dialect, ast); - ForLoopConditionIntoBody{_dialect}(ast); - UnusedPruner::runUntilStabilisedOnFullAST(_dialect, ast, reservedIdentifiers); - CommonSubexpressionEliminator::run(_dialect, ast); + suite.runSequence({ + SSATransform::name, + RedundantAssignEliminator::name, + RedundantAssignEliminator::name, + LoadResolver::name, + ExpressionSimplifier::name, + LiteralRematerialiser::name, + ForLoopConditionOutOfBody::name, + StructuralSimplifier::name, + BlockFlattener::name, + DeadCodeEliminator::name, + ControlFlowSimplifier::name, + CommonSubexpressionEliminator::name, + SSATransform::name, + RedundantAssignEliminator::name, + RedundantAssignEliminator::name, + ForLoopConditionIntoBody::name, + UnusedPruner::name, + CommonSubexpressionEliminator::name, + }, ast); } } // Make source short and pretty. - ExpressionJoiner::run(ast); - Rematerialiser::run(_dialect, ast); - UnusedPruner::runUntilStabilisedOnFullAST(_dialect, ast, reservedIdentifiers); - ExpressionJoiner::run(ast); - UnusedPruner::runUntilStabilisedOnFullAST(_dialect, ast, reservedIdentifiers); - ExpressionJoiner::run(ast); - UnusedPruner::runUntilStabilisedOnFullAST(_dialect, ast, reservedIdentifiers); + suite.runSequence({ + ExpressionJoiner::name, + Rematerialiser::name, + UnusedPruner::name, + ExpressionJoiner::name, + UnusedPruner::name, + ExpressionJoiner::name, + UnusedPruner::name, - SSAReverser::run(ast); - CommonSubexpressionEliminator::run(_dialect, ast); - LiteralRematerialiser{_dialect}(ast); - ForLoopConditionOutOfBody{_dialect}(ast); - CommonSubexpressionEliminator::run(_dialect, ast); - UnusedPruner::runUntilStabilisedOnFullAST(_dialect, ast, reservedIdentifiers); + SSAReverser::name, + CommonSubexpressionEliminator::name, + LiteralRematerialiser::name, + ForLoopConditionOutOfBody::name, + CommonSubexpressionEliminator::name, + UnusedPruner::name, - ExpressionJoiner::run(ast); - Rematerialiser::run(_dialect, ast); - UnusedPruner::runUntilStabilisedOnFullAST(_dialect, ast, reservedIdentifiers); + ExpressionJoiner::name, + Rematerialiser::name, + UnusedPruner::name, + }, ast); // This is a tuning parameter, but actually just prevents infinite loops. size_t stackCompressorMaxIterations = 16; - FunctionGrouper{}(ast); + suite.runSequence({ + FunctionGrouper::name + }, ast); // We ignore the return value because we will get a much better error // message once we perform code generation. StackCompressor::run( @@ -237,14 +257,16 @@ void OptimiserSuite::run( _optimizeStackAllocation, stackCompressorMaxIterations ); - BlockFlattener{}(ast); - DeadCodeEliminator{_dialect}(ast); - ControlFlowSimplifier{_dialect}(ast); - LiteralRematerialiser{_dialect}(ast); - ForLoopConditionOutOfBody{_dialect}(ast); - CommonSubexpressionEliminator::run(_dialect, ast); + suite.runSequence({ + BlockFlattener::name, + DeadCodeEliminator::name, + ControlFlowSimplifier::name, + LiteralRematerialiser::name, + ForLoopConditionOutOfBody::name, + CommonSubexpressionEliminator::name, - FunctionGrouper{}(ast); + FunctionGrouper::name, + }, ast); if (EVMDialect const* dialect = dynamic_cast(&_dialect)) { @@ -258,7 +280,73 @@ void OptimiserSuite::run( if (ast.statements.size() > 1 && boost::get(ast.statements.front()).statements.empty()) ast.statements.erase(ast.statements.begin()); } - VarNameCleaner{ast, _dialect, reservedIdentifiers}(ast); + suite.runSequence({ + VarNameCleaner::name + }, ast); *_object.analysisInfo = AsmAnalyzer::analyzeStrictAssertCorrect(_dialect, _object); } + +namespace +{ + + +template +map> optimiserStepCollection() +{ + map> ret; + for (unique_ptr& s: make_vector>( + (make_unique>())... + )) + { + yulAssert(!ret.count(s->name), ""); + ret[s->name] = std::move(s); + } + return ret; +} + +} + +map> const& OptimiserSuite::allSteps() +{ + static map> instance; + if (instance.empty()) + instance = optimiserStepCollection< + BlockFlattener, + CommonSubexpressionEliminator, + ControlFlowSimplifier, + DeadCodeEliminator, + EquivalentFunctionCombiner, + ExpressionInliner, + ExpressionJoiner, + ExpressionSimplifier, + ExpressionSplitter, + ForLoopConditionIntoBody, + ForLoopConditionOutOfBody, + ForLoopInitRewriter, + FullInliner, + FunctionGrouper, + FunctionHoister, + LiteralRematerialiser, + LoadResolver, + RedundantAssignEliminator, + Rematerialiser, + SSAReverser, + SSATransform, + StructuralSimplifier, + UnusedPruner, + VarDeclInitializer, + VarNameCleaner + >(); + return instance; +} + +void OptimiserSuite::runSequence(std::vector const& _steps, Block& _ast) +{ + for (string const& step: _steps) + { + if (m_debug == Debug::PrintStep) + cout << "Running " << step << endl; + allSteps().at(step)->run(m_context, _ast); + } +} diff --git a/libyul/optimiser/Suite.h b/libyul/optimiser/Suite.h index 137066bd9..f47574799 100644 --- a/libyul/optimiser/Suite.h +++ b/libyul/optimiser/Suite.h @@ -22,9 +22,13 @@ #include #include +#include +#include #include #include +#include +#include namespace yul { @@ -41,6 +45,11 @@ struct Object; class OptimiserSuite { public: + enum class Debug + { + None, + PrintStep + }; static void run( Dialect const& _dialect, GasMeter const* _meter, @@ -48,6 +57,26 @@ public: bool _optimizeStackAllocation, std::set const& _externallyUsedIdentifiers = {} ); + + void runSequence(std::vector const& _steps, Block& _ast); + + static std::map> const& allSteps(); + +private: + OptimiserSuite( + Dialect const& _dialect, + std::set const& _externallyUsedIdentifiers, + Debug _debug, + Block& _ast + ): + m_dispenser{_dialect, _ast, _externallyUsedIdentifiers}, + m_context{_dialect, m_dispenser, _externallyUsedIdentifiers}, + m_debug(_debug) + {} + + NameDispenser m_dispenser; + OptimiserStepContext m_context; + Debug m_debug; }; } diff --git a/libyul/optimiser/UnusedPruner.h b/libyul/optimiser/UnusedPruner.h index 626730f65..d0454243d 100644 --- a/libyul/optimiser/UnusedPruner.h +++ b/libyul/optimiser/UnusedPruner.h @@ -21,6 +21,7 @@ #pragma once #include +#include #include #include @@ -47,19 +48,11 @@ struct SideEffects; class UnusedPruner: public ASTModifier { public: - UnusedPruner( - Dialect const& _dialect, - Block& _ast, - bool _allowMSizeOptimization, - std::map const* _functionSideEffects = nullptr, - std::set const& _externallyUsedFunctions = {} - ); - UnusedPruner( - Dialect const& _dialect, - FunctionDefinition& _function, - bool _allowMSizeOptimization, - std::set const& _externallyUsedFunctions = {} - ); + static constexpr char const* name{"UnusedPruner"}; + static void run(OptimiserStepContext& _context, Block& _ast) { + UnusedPruner::runUntilStabilisedOnFullAST(_context.dialect, _ast, _context.reservedIdentifiers); + } + using ASTModifier::operator(); void operator()(Block& _block) override; @@ -76,6 +69,15 @@ public: std::set const& _externallyUsedFunctions = {} ); + static void run( + Dialect const& _dialect, + Block& _ast, + std::set const& _externallyUsedFunctions = {} + ) + { + runUntilStabilisedOnFullAST(_dialect, _ast, _externallyUsedFunctions); + } + /// Run the pruner until the code does not change anymore. /// The provided block has to be a full AST. /// The pruner itself determines if msize is used and which user-defined functions @@ -99,6 +101,20 @@ public: ); private: + UnusedPruner( + Dialect const& _dialect, + Block& _ast, + bool _allowMSizeOptimization, + std::map const* _functionSideEffects = nullptr, + std::set const& _externallyUsedFunctions = {} + ); + UnusedPruner( + Dialect const& _dialect, + FunctionDefinition& _function, + bool _allowMSizeOptimization, + std::set const& _externallyUsedFunctions = {} + ); + bool used(YulString _name) const; void subtractReferences(std::map const& _subtrahend); diff --git a/libyul/optimiser/VarDeclInitializer.h b/libyul/optimiser/VarDeclInitializer.h index 41d0917ce..ea3ca2988 100644 --- a/libyul/optimiser/VarDeclInitializer.h +++ b/libyul/optimiser/VarDeclInitializer.h @@ -19,6 +19,7 @@ #include #include +#include namespace yul { @@ -32,6 +33,9 @@ namespace yul class VarDeclInitializer: public ASTModifier { public: + static constexpr char const* name{"VarDeclInitializer"}; + static void run(OptimiserStepContext&, Block& _ast) { VarDeclInitializer{}(_ast); } + void operator()(Block& _block) override; }; diff --git a/libyul/optimiser/VarNameCleaner.h b/libyul/optimiser/VarNameCleaner.h index 7f2e90989..246152deb 100644 --- a/libyul/optimiser/VarNameCleaner.h +++ b/libyul/optimiser/VarNameCleaner.h @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -43,11 +44,11 @@ struct Dialect; class VarNameCleaner: public ASTModifier { public: - VarNameCleaner( - Block const& _ast, - Dialect const& _dialect, - std::set _blacklist = {} - ); + static constexpr char const* name{"VarNameCleaner"}; + static void run(OptimiserStepContext& _context, Block& _ast) + { + VarNameCleaner{_ast, _context.dialect, _context.reservedIdentifiers}(_ast); + } using ASTModifier::operator(); void operator()(VariableDeclaration& _varDecl) override; @@ -55,6 +56,12 @@ public: void operator()(FunctionDefinition& _funDef) override; private: + VarNameCleaner( + Block const& _ast, + Dialect const& _dialect, + std::set _blacklist = {} + ); + /// Tries to rename a list of variables. void renameVariables(std::vector& _variables); diff --git a/test/libyul/YulOptimizerTest.cpp b/test/libyul/YulOptimizerTest.cpp index 399d39b55..c8fb703f2 100644 --- a/test/libyul/YulOptimizerTest.cpp +++ b/test/libyul/YulOptimizerTest.cpp @@ -45,6 +45,7 @@ #include #include #include +#include #include #include #include @@ -114,21 +115,23 @@ TestCase::TestResult YulOptimizerTest::run(ostream& _stream, string const& _line return TestResult::FatalError; soltestAssert(m_dialect, "Dialect not set."); + + updateContext(); + if (m_optimizerStep == "disambiguator") disambiguate(); else if (m_optimizerStep == "nameDisplacer") { disambiguate(); - NameDispenser nameDispenser{*m_dialect, *m_ast}; NameDisplacer{ - nameDispenser, + *m_nameDispenser, {"illegal1"_yulstring, "illegal2"_yulstring, "illegal3"_yulstring, "illegal4"_yulstring, "illegal5"_yulstring} }(*m_ast); } else if (m_optimizerStep == "blockFlattener") { disambiguate(); - BlockFlattener{}(*m_ast); + BlockFlattener::run(*m_context, *m_ast); } else if (m_optimizerStep == "constantOptimiser") { @@ -136,193 +139,182 @@ TestCase::TestResult YulOptimizerTest::run(ostream& _stream, string const& _line ConstantOptimiser{dynamic_cast(*m_dialect), meter}(*m_ast); } else if (m_optimizerStep == "varDeclInitializer") - VarDeclInitializer{}(*m_ast); + VarDeclInitializer::run(*m_context, *m_ast); else if (m_optimizerStep == "varNameCleaner") - VarNameCleaner{*m_ast, *m_dialect}(*m_ast); + VarNameCleaner::run(*m_context, *m_ast); else if (m_optimizerStep == "forLoopConditionIntoBody") { disambiguate(); - ForLoopConditionIntoBody{*m_dialect}(*m_ast); + ForLoopConditionIntoBody::run(*m_context, *m_ast); } else if (m_optimizerStep == "forLoopInitRewriter") { disambiguate(); - ForLoopInitRewriter{}(*m_ast); + ForLoopInitRewriter::run(*m_context, *m_ast); } else if (m_optimizerStep == "commonSubexpressionEliminator") { disambiguate(); - CommonSubexpressionEliminator::run(*m_dialect, *m_ast); + CommonSubexpressionEliminator::run(*m_context, *m_ast); } else if (m_optimizerStep == "expressionSplitter") - { - NameDispenser nameDispenser{*m_dialect, *m_ast}; - ExpressionSplitter{*m_dialect, nameDispenser}(*m_ast); - } + ExpressionSplitter::run(*m_context, *m_ast); else if (m_optimizerStep == "expressionJoiner") { disambiguate(); - ExpressionJoiner::run(*m_ast); + ExpressionJoiner::run(*m_context, *m_ast); } else if (m_optimizerStep == "splitJoin") { disambiguate(); - NameDispenser nameDispenser{*m_dialect, *m_ast}; - ExpressionSplitter{*m_dialect, nameDispenser}(*m_ast); - ExpressionJoiner::run(*m_ast); - ExpressionJoiner::run(*m_ast); + ExpressionSplitter::run(*m_context, *m_ast); + ExpressionJoiner::run(*m_context, *m_ast); + ExpressionJoiner::run(*m_context, *m_ast); } else if (m_optimizerStep == "functionGrouper") { disambiguate(); - (FunctionGrouper{})(*m_ast); + FunctionGrouper::run(*m_context, *m_ast); } else if (m_optimizerStep == "functionHoister") { disambiguate(); - (FunctionHoister{})(*m_ast); + FunctionHoister::run(*m_context, *m_ast); } else if (m_optimizerStep == "expressionInliner") { disambiguate(); - ExpressionInliner(*m_dialect, *m_ast).run(); + ExpressionInliner::run(*m_context, *m_ast); } else if (m_optimizerStep == "fullInliner") { disambiguate(); - (FunctionHoister{})(*m_ast); - (FunctionGrouper{})(*m_ast); - NameDispenser nameDispenser{*m_dialect, *m_ast}; - ExpressionSplitter{*m_dialect, nameDispenser}(*m_ast); - FullInliner(*m_ast, nameDispenser).run(); - ExpressionJoiner::run(*m_ast); + FunctionHoister::run(*m_context, *m_ast); + FunctionGrouper::run(*m_context, *m_ast); + ExpressionSplitter::run(*m_context, *m_ast); + FullInliner::run(*m_context, *m_ast); + ExpressionJoiner::run(*m_context, *m_ast); } else if (m_optimizerStep == "mainFunction") { disambiguate(); - (FunctionGrouper{})(*m_ast); - (MainFunction{})(*m_ast); + FunctionGrouper::run(*m_context, *m_ast); + MainFunction::run(*m_context, *m_ast); } else if (m_optimizerStep == "rematerialiser") { disambiguate(); - Rematerialiser::run(*m_dialect, *m_ast); + Rematerialiser::run(*m_context, *m_ast); } else if (m_optimizerStep == "expressionSimplifier") { disambiguate(); - ExpressionSimplifier::run(*m_dialect, *m_ast); - ExpressionSimplifier::run(*m_dialect, *m_ast); - ExpressionSimplifier::run(*m_dialect, *m_ast); + ExpressionSimplifier::run(*m_context, *m_ast); + ExpressionSimplifier::run(*m_context, *m_ast); + ExpressionSimplifier::run(*m_context, *m_ast); } else if (m_optimizerStep == "fullSimplify") { disambiguate(); - NameDispenser nameDispenser{*m_dialect, *m_ast}; - ExpressionSplitter{*m_dialect, nameDispenser}(*m_ast); - ForLoopInitRewriter{}(*m_ast); - CommonSubexpressionEliminator::run(*m_dialect, *m_ast); - ExpressionSimplifier::run(*m_dialect, *m_ast); - UnusedPruner::runUntilStabilisedOnFullAST(*m_dialect, *m_ast); - DeadCodeEliminator{*m_dialect}(*m_ast); - ExpressionJoiner::run(*m_ast); - ExpressionJoiner::run(*m_ast); + ExpressionSplitter::run(*m_context, *m_ast); + ForLoopInitRewriter::run(*m_context, *m_ast); + CommonSubexpressionEliminator::run(*m_context, *m_ast); + ExpressionSimplifier::run(*m_context, *m_ast); + UnusedPruner::run(*m_context, *m_ast); + DeadCodeEliminator::run(*m_context, *m_ast); + ExpressionJoiner::run(*m_context, *m_ast); + ExpressionJoiner::run(*m_context, *m_ast); } else if (m_optimizerStep == "unusedPruner") { disambiguate(); - UnusedPruner::runUntilStabilisedOnFullAST(*m_dialect, *m_ast); + UnusedPruner::run(*m_context, *m_ast); } else if (m_optimizerStep == "deadCodeEliminator") { disambiguate(); - ForLoopInitRewriter{}(*m_ast); - DeadCodeEliminator{*m_dialect}(*m_ast); + ForLoopInitRewriter::run(*m_context, *m_ast); + DeadCodeEliminator::run(*m_context, *m_ast); } else if (m_optimizerStep == "ssaTransform") { disambiguate(); - NameDispenser nameDispenser{*m_dialect, *m_ast}; - SSATransform::run(*m_ast, nameDispenser); + SSATransform::run(*m_context, *m_ast); } else if (m_optimizerStep == "redundantAssignEliminator") { disambiguate(); - RedundantAssignEliminator::run(*m_dialect, *m_ast); + RedundantAssignEliminator::run(*m_context, *m_ast); } else if (m_optimizerStep == "ssaPlusCleanup") { disambiguate(); - NameDispenser nameDispenser{*m_dialect, *m_ast}; - SSATransform::run(*m_ast, nameDispenser); - RedundantAssignEliminator::run(*m_dialect, *m_ast); + SSATransform::run(*m_context, *m_ast); + RedundantAssignEliminator::run(*m_context, *m_ast); } else if (m_optimizerStep == "loadResolver") { disambiguate(); - ForLoopInitRewriter{}(*m_ast); - NameDispenser nameDispenser{*m_dialect, *m_ast}; - ExpressionSplitter{*m_dialect, nameDispenser}(*m_ast); - CommonSubexpressionEliminator::run(*m_dialect, *m_ast); - ExpressionSimplifier::run(*m_dialect, *m_ast); + ForLoopInitRewriter::run(*m_context, *m_ast); + ExpressionSplitter::run(*m_context, *m_ast); + CommonSubexpressionEliminator::run(*m_context, *m_ast); + ExpressionSimplifier::run(*m_context, *m_ast); - LoadResolver::run(*m_dialect, *m_ast); + LoadResolver::run(*m_context, *m_ast); - UnusedPruner::runUntilStabilisedOnFullAST(*m_dialect, *m_ast); - ExpressionJoiner::run(*m_ast); - ExpressionJoiner::run(*m_ast); + UnusedPruner::run(*m_context, *m_ast); + ExpressionJoiner::run(*m_context, *m_ast); + ExpressionJoiner::run(*m_context, *m_ast); } else if (m_optimizerStep == "controlFlowSimplifier") { disambiguate(); - ControlFlowSimplifier{*m_dialect}(*m_ast); + ControlFlowSimplifier::run(*m_context, *m_ast); } else if (m_optimizerStep == "structuralSimplifier") { disambiguate(); - ForLoopInitRewriter{}(*m_ast); - LiteralRematerialiser{*m_dialect}(*m_ast); - StructuralSimplifier{}(*m_ast); + ForLoopInitRewriter::run(*m_context, *m_ast); + LiteralRematerialiser::run(*m_context, *m_ast); + StructuralSimplifier::run(*m_context, *m_ast); } else if (m_optimizerStep == "equivalentFunctionCombiner") { disambiguate(); - EquivalentFunctionCombiner::run(*m_ast); + EquivalentFunctionCombiner::run(*m_context, *m_ast); } else if (m_optimizerStep == "ssaReverser") { disambiguate(); - SSAReverser::run(*m_ast); + SSAReverser::run(*m_context, *m_ast); } else if (m_optimizerStep == "ssaAndBack") { disambiguate(); // apply SSA - NameDispenser nameDispenser{*m_dialect, *m_ast}; - SSATransform::run(*m_ast, nameDispenser); - RedundantAssignEliminator::run(*m_dialect, *m_ast); + SSATransform::run(*m_context, *m_ast); + RedundantAssignEliminator::run(*m_context, *m_ast); // reverse SSA - SSAReverser::run(*m_ast); - CommonSubexpressionEliminator::run(*m_dialect, *m_ast); - UnusedPruner::runUntilStabilisedOnFullAST(*m_dialect, *m_ast); + SSAReverser::run(*m_context, *m_ast); + CommonSubexpressionEliminator::run(*m_context, *m_ast); + UnusedPruner::run(*m_context, *m_ast); } else if (m_optimizerStep == "stackCompressor") { disambiguate(); - (FunctionGrouper{})(*m_ast); + FunctionGrouper::run(*m_context, *m_ast); size_t maxIterations = 16; Object obj; obj.code = m_ast; StackCompressor::run(*m_dialect, obj, true, maxIterations); m_ast = obj.code; - (BlockFlattener{})(*m_ast); + BlockFlattener::run(*m_context, *m_ast); } else if (m_optimizerStep == "wordSizeTransform") { disambiguate(); - NameDispenser nameDispenser{*m_dialect, *m_ast}; - ExpressionSplitter{*m_dialect, nameDispenser}(*m_ast); - WordSizeTransform::run(*m_dialect, *m_ast, nameDispenser); + ExpressionSplitter::run(*m_context, *m_ast); + WordSizeTransform::run(*m_dialect, *m_ast, *m_nameDispenser); } else if (m_optimizerStep == "fullSuite") { @@ -413,6 +405,13 @@ void YulOptimizerTest::disambiguate() { *m_ast = boost::get(Disambiguator(*m_dialect, *m_analysisInfo)(*m_ast)); m_analysisInfo.reset(); + updateContext(); +} + +void YulOptimizerTest::updateContext() +{ + m_nameDispenser = make_unique(*m_dialect, *m_ast, m_reservedIdentifiers); + m_context = unique_ptr(new OptimiserStepContext{*m_dialect, *m_nameDispenser, m_reservedIdentifiers}); } void YulOptimizerTest::printErrors(ostream& _stream, ErrorList const& _errors) diff --git a/test/libyul/YulOptimizerTest.h b/test/libyul/YulOptimizerTest.h index 16bafcf0b..87248cfad 100644 --- a/test/libyul/YulOptimizerTest.h +++ b/test/libyul/YulOptimizerTest.h @@ -19,6 +19,14 @@ #include +#include +#include + +#include + +#include +#include + namespace langutil { class Scanner; @@ -58,6 +66,7 @@ private: void printIndented(std::ostream& _stream, std::string const& _output, std::string const& _linePrefix = "") const; bool parse(std::ostream& _stream, std::string const& _linePrefix, bool const _formatted); void disambiguate(); + void updateContext(); static void printErrors(std::ostream& _stream, langutil::ErrorList const& _errors); @@ -67,6 +76,10 @@ private: std::string m_expectation; Dialect const* m_dialect = nullptr; + std::set m_reservedIdentifiers; + std::unique_ptr m_nameDispenser; + std::unique_ptr m_context; + std::shared_ptr m_ast; std::shared_ptr m_analysisInfo; std::string m_obtainedResult; diff --git a/test/tools/yulopti.cpp b/test/tools/yulopti.cpp index d84f8b6d1..7d0b1d952 100644 --- a/test/tools/yulopti.cpp +++ b/test/tools/yulopti.cpp @@ -51,6 +51,7 @@ #include #include #include +#include #include #include #include @@ -126,11 +127,12 @@ public: cout << source << endl; if (!parse(source)) return; + set reservedIdentifiers; if (!disambiguated) { *m_ast = boost::get(Disambiguator(m_dialect, *m_analysisInfo)(*m_ast)); m_analysisInfo.reset(); - m_nameDispenser = make_shared(m_dialect, *m_ast); + m_nameDispenser = make_shared(m_dialect, *m_ast, reservedIdentifiers); disambiguated = true; } cout << "(q)quit/(f)flatten/(c)se/initialize var(d)ecls/(x)plit/(j)oin/(g)rouper/(h)oister/" << endl; @@ -141,78 +143,83 @@ public: cout.flush(); int option = readStandardInputChar(); cout << ' ' << char(option) << endl; + + OptimiserStepContext context{m_dialect, *m_nameDispenser, reservedIdentifiers}; switch (option) { case 'q': return; case 'f': - BlockFlattener{}(*m_ast); + BlockFlattener::run(context, *m_ast); break; case 'o': - ForLoopInitRewriter{}(*m_ast); + ForLoopInitRewriter::run(context, *m_ast); break; case 'O': - ForLoopConditionOutOfBody{m_dialect}(*m_ast); + ForLoopConditionOutOfBody::run(context, *m_ast); break; case 'I': - ForLoopConditionIntoBody{m_dialect}(*m_ast); + ForLoopConditionIntoBody::run(context, *m_ast); break; case 'c': - CommonSubexpressionEliminator::run(m_dialect, *m_ast); + CommonSubexpressionEliminator::run(context, *m_ast); break; case 'd': - (VarDeclInitializer{})(*m_ast); + VarDeclInitializer::run(context, *m_ast); break; case 'l': - VarNameCleaner{*m_ast, m_dialect}(*m_ast); + VarNameCleaner::run(context, *m_ast); break; case 'x': - ExpressionSplitter{m_dialect, *m_nameDispenser}(*m_ast); + ExpressionSplitter::run(context, *m_ast); break; case 'j': - ExpressionJoiner::run(*m_ast); + ExpressionJoiner::run(context, *m_ast); break; case 'g': - (FunctionGrouper{})(*m_ast); + FunctionGrouper::run(context, *m_ast); break; case 'h': - (FunctionHoister{})(*m_ast); + FunctionHoister::run(context, *m_ast); break; case 'e': - ExpressionInliner{m_dialect, *m_ast}.run(); + ExpressionInliner::run(context, *m_ast); break; case 'i': - FullInliner(*m_ast, *m_nameDispenser).run(); + FullInliner::run(context, *m_ast); break; case 's': - ExpressionSimplifier::run(m_dialect, *m_ast); + ExpressionSimplifier::run(context, *m_ast); break; case 't': - StructuralSimplifier{}(*m_ast); + StructuralSimplifier::run(context, *m_ast); + break; + case 'T': + LiteralRematerialiser::run(context, *m_ast); break; case 'n': - (ControlFlowSimplifier{m_dialect})(*m_ast); + ControlFlowSimplifier::run(context, *m_ast); break; case 'u': - UnusedPruner::runUntilStabilisedOnFullAST(m_dialect, *m_ast); + UnusedPruner::run(context, *m_ast); break; case 'D': - DeadCodeEliminator{m_dialect}(*m_ast); + DeadCodeEliminator::run(context, *m_ast); break; case 'a': - SSATransform::run(*m_ast, *m_nameDispenser); + SSATransform::run(context, *m_ast); break; case 'r': - RedundantAssignEliminator::run(m_dialect, *m_ast); + RedundantAssignEliminator::run(context, *m_ast); break; case 'm': - Rematerialiser::run(m_dialect, *m_ast); + Rematerialiser::run(context, *m_ast); break; case 'v': - EquivalentFunctionCombiner::run(*m_ast); + EquivalentFunctionCombiner::run(context, *m_ast); break; case 'V': - SSAReverser::run(*m_ast); + SSAReverser::run(context, *m_ast); break; case 'p': { @@ -222,7 +229,7 @@ public: break; } case 'L': - LoadResolver::run(m_dialect, *m_ast); + LoadResolver::run(context, *m_ast); break; default: cout << "Unknown option." << endl;