diff options
Diffstat (limited to 'libyul')
-rw-r--r-- | libyul/AsmPrinter.cpp | 30 | ||||
-rw-r--r-- | libyul/AsmPrinter.h | 30 | ||||
-rw-r--r-- | libyul/CMakeLists.txt | 2 | ||||
-rw-r--r-- | libyul/optimiser/DataFlowAnalyzer.cpp | 12 | ||||
-rw-r--r-- | libyul/optimiser/DataFlowAnalyzer.h | 2 | ||||
-rw-r--r-- | libyul/optimiser/FullInliner.cpp | 23 | ||||
-rw-r--r-- | libyul/optimiser/FullInliner.h | 7 | ||||
-rw-r--r-- | libyul/optimiser/Metrics.cpp | 3 | ||||
-rw-r--r-- | libyul/optimiser/Metrics.h | 12 | ||||
-rw-r--r-- | libyul/optimiser/SSAValueTracker.cpp | 16 | ||||
-rw-r--r-- | libyul/optimiser/SSAValueTracker.h | 3 | ||||
-rw-r--r-- | libyul/optimiser/Suite.cpp | 9 | ||||
-rw-r--r-- | libyul/optimiser/VarDeclInitializer.cpp | 56 | ||||
-rw-r--r-- | libyul/optimiser/VarDeclInitializer.h | 38 | ||||
-rw-r--r-- | libyul/optimiser/VarDeclPropagator.cpp | 126 | ||||
-rw-r--r-- | libyul/optimiser/VarDeclPropagator.h | 60 |
16 files changed, 189 insertions, 240 deletions
diff --git a/libyul/AsmPrinter.cpp b/libyul/AsmPrinter.cpp index 4bea1f36..b7af4778 100644 --- a/libyul/AsmPrinter.cpp +++ b/libyul/AsmPrinter.cpp @@ -40,14 +40,14 @@ using namespace dev::solidity; //@TODO source locations -string AsmPrinter::operator()(yul::Instruction const& _instruction) +string AsmPrinter::operator()(yul::Instruction const& _instruction) const { solAssert(!m_yul, ""); solAssert(isValidInstruction(_instruction.instruction), "Invalid instruction"); return boost::to_lower_copy(instructionInfo(_instruction.instruction).name); } -string AsmPrinter::operator()(Literal const& _literal) +string AsmPrinter::operator()(Literal const& _literal) const { switch (_literal.kind) { @@ -90,13 +90,13 @@ string AsmPrinter::operator()(Literal const& _literal) return "\"" + out + "\"" + appendTypeName(_literal.type); } -string AsmPrinter::operator()(Identifier const& _identifier) +string AsmPrinter::operator()(Identifier const& _identifier) const { solAssert(!_identifier.name.empty(), "Invalid identifier."); return _identifier.name.str(); } -string AsmPrinter::operator()(FunctionalInstruction const& _functionalInstruction) +string AsmPrinter::operator()(FunctionalInstruction const& _functionalInstruction) const { solAssert(!m_yul, ""); solAssert(isValidInstruction(_functionalInstruction.instruction), "Invalid instruction"); @@ -109,26 +109,26 @@ string AsmPrinter::operator()(FunctionalInstruction const& _functionalInstructio ")"; } -string AsmPrinter::operator()(ExpressionStatement const& _statement) +string AsmPrinter::operator()(ExpressionStatement const& _statement) const { return boost::apply_visitor(*this, _statement.expression); } -string AsmPrinter::operator()(Label const& _label) +string AsmPrinter::operator()(Label const& _label) const { solAssert(!m_yul, ""); solAssert(!_label.name.empty(), "Invalid label."); return _label.name.str() + ":"; } -string AsmPrinter::operator()(StackAssignment const& _assignment) +string AsmPrinter::operator()(StackAssignment const& _assignment) const { solAssert(!m_yul, ""); solAssert(!_assignment.variableName.name.empty(), "Invalid variable name."); return "=: " + (*this)(_assignment.variableName); } -string AsmPrinter::operator()(Assignment const& _assignment) +string AsmPrinter::operator()(Assignment const& _assignment) const { solAssert(_assignment.variableNames.size() >= 1, ""); string variables = (*this)(_assignment.variableNames.front()); @@ -137,7 +137,7 @@ string AsmPrinter::operator()(Assignment const& _assignment) return variables + " := " + boost::apply_visitor(*this, *_assignment.value); } -string AsmPrinter::operator()(VariableDeclaration const& _variableDeclaration) +string AsmPrinter::operator()(VariableDeclaration const& _variableDeclaration) const { string out = "let "; out += boost::algorithm::join( @@ -154,7 +154,7 @@ string AsmPrinter::operator()(VariableDeclaration const& _variableDeclaration) return out; } -string AsmPrinter::operator()(FunctionDefinition const& _functionDefinition) +string AsmPrinter::operator()(FunctionDefinition const& _functionDefinition) const { solAssert(!_functionDefinition.name.empty(), "Invalid function name."); string out = "function " + _functionDefinition.name.str() + "("; @@ -179,7 +179,7 @@ string AsmPrinter::operator()(FunctionDefinition const& _functionDefinition) return out + "\n" + (*this)(_functionDefinition.body); } -string AsmPrinter::operator()(FunctionCall const& _functionCall) +string AsmPrinter::operator()(FunctionCall const& _functionCall) const { return (*this)(_functionCall.functionName) + "(" + @@ -189,13 +189,13 @@ string AsmPrinter::operator()(FunctionCall const& _functionCall) ")"; } -string AsmPrinter::operator()(If const& _if) +string AsmPrinter::operator()(If const& _if) const { solAssert(_if.condition, "Invalid if condition."); return "if " + boost::apply_visitor(*this, *_if.condition) + "\n" + (*this)(_if.body); } -string AsmPrinter::operator()(Switch const& _switch) +string AsmPrinter::operator()(Switch const& _switch) const { solAssert(_switch.expression, "Invalid expression pointer."); string out = "switch " + boost::apply_visitor(*this, *_switch.expression); @@ -210,7 +210,7 @@ string AsmPrinter::operator()(Switch const& _switch) return out; } -string AsmPrinter::operator()(ForLoop const& _forLoop) +string AsmPrinter::operator()(ForLoop const& _forLoop) const { solAssert(_forLoop.condition, "Invalid for loop condition."); string out = "for "; @@ -224,7 +224,7 @@ string AsmPrinter::operator()(ForLoop const& _forLoop) return out; } -string AsmPrinter::operator()(Block const& _block) +string AsmPrinter::operator()(Block const& _block) const { if (_block.statements.empty()) return "{\n}"; diff --git a/libyul/AsmPrinter.h b/libyul/AsmPrinter.h index 61dfc18c..a1b9d6cd 100644 --- a/libyul/AsmPrinter.h +++ b/libyul/AsmPrinter.h @@ -36,21 +36,21 @@ class AsmPrinter: public boost::static_visitor<std::string> public: explicit AsmPrinter(bool _yul = false): m_yul(_yul) {} - std::string operator()(Instruction const& _instruction); - std::string operator()(Literal const& _literal); - std::string operator()(Identifier const& _identifier); - std::string operator()(FunctionalInstruction const& _functionalInstruction); - std::string operator()(ExpressionStatement const& _expr); - std::string operator()(Label const& _label); - std::string operator()(StackAssignment const& _assignment); - std::string operator()(Assignment const& _assignment); - std::string operator()(VariableDeclaration const& _variableDeclaration); - std::string operator()(FunctionDefinition const& _functionDefinition); - std::string operator()(FunctionCall const& _functionCall); - std::string operator()(If const& _if); - std::string operator()(Switch const& _switch); - std::string operator()(ForLoop const& _forLoop); - std::string operator()(Block const& _block); + std::string operator()(Instruction const& _instruction) const; + std::string operator()(Literal const& _literal) const; + std::string operator()(Identifier const& _identifier) const; + std::string operator()(FunctionalInstruction const& _functionalInstruction) const; + std::string operator()(ExpressionStatement const& _expr) const; + std::string operator()(Label const& _label) const; + std::string operator()(StackAssignment const& _assignment) const; + std::string operator()(Assignment const& _assignment) const; + std::string operator()(VariableDeclaration const& _variableDeclaration) const; + std::string operator()(FunctionDefinition const& _functionDefinition) const; + std::string operator()(FunctionCall const& _functionCall) const; + std::string operator()(If const& _if) const; + std::string operator()(Switch const& _switch) const; + std::string operator()(ForLoop const& _forLoop) const; + std::string operator()(Block const& _block) const; private: std::string formatTypedName(TypedName _variable) const; diff --git a/libyul/CMakeLists.txt b/libyul/CMakeLists.txt index 74a5703c..5a86d2a2 100644 --- a/libyul/CMakeLists.txt +++ b/libyul/CMakeLists.txt @@ -43,6 +43,6 @@ add_library(yul optimiser/SyntacticalEquality.cpp optimiser/UnusedPruner.cpp optimiser/Utilities.cpp - optimiser/VarDeclPropagator.cpp + optimiser/VarDeclInitializer.cpp ) target_link_libraries(yul PUBLIC evmasm devcore langutil) diff --git a/libyul/optimiser/DataFlowAnalyzer.cpp b/libyul/optimiser/DataFlowAnalyzer.cpp index 64c67b38..c8d236dc 100644 --- a/libyul/optimiser/DataFlowAnalyzer.cpp +++ b/libyul/optimiser/DataFlowAnalyzer.cpp @@ -96,7 +96,10 @@ void DataFlowAnalyzer::operator()(FunctionDefinition& _fun) for (auto const& parameter: _fun.parameters) m_variableScopes.back().variables.emplace(parameter.name); for (auto const& var: _fun.returnVariables) + { m_variableScopes.back().variables.emplace(var.name); + handleAssignment({var.name}, nullptr); + } ASTModifier::operator()(_fun); popScope(); @@ -136,17 +139,22 @@ void DataFlowAnalyzer::operator()(Block& _block) void DataFlowAnalyzer::handleAssignment(set<YulString> const& _variables, Expression* _value) { + static Expression const zero{Literal{{}, LiteralKind::Number, YulString{"0"}, {}}}; clearValues(_variables); MovableChecker movableChecker; if (_value) movableChecker.visit(*_value); - if (_variables.size() == 1) + else + for (auto const& var: _variables) + m_value[var] = &zero; + + if (_value && _variables.size() == 1) { YulString name = *_variables.begin(); // Expression has to be movable and cannot contain a reference // to the variable that will be assigned to. - if (_value && movableChecker.movable() && !movableChecker.referencedVariables().count(name)) + if (movableChecker.movable() && !movableChecker.referencedVariables().count(name)) m_value[name] = _value; } diff --git a/libyul/optimiser/DataFlowAnalyzer.h b/libyul/optimiser/DataFlowAnalyzer.h index cd134d48..4f12ff6a 100644 --- a/libyul/optimiser/DataFlowAnalyzer.h +++ b/libyul/optimiser/DataFlowAnalyzer.h @@ -36,6 +36,8 @@ namespace yul * Tracks assignments and is used as base class for both Rematerialiser and * Common Subexpression Eliminator. * + * A special zero constant expression is used for the default value of variables. + * * Prerequisite: Disambiguator */ class DataFlowAnalyzer: public ASTModifier diff --git a/libyul/optimiser/FullInliner.cpp b/libyul/optimiser/FullInliner.cpp index f69f7cdd..95360dc3 100644 --- a/libyul/optimiser/FullInliner.cpp +++ b/libyul/optimiser/FullInliner.cpp @@ -49,6 +49,8 @@ FullInliner::FullInliner(Block& _ast, NameDispenser& _dispenser): if (ssaValue.second && ssaValue.second->type() == typeid(Literal)) m_constants.emplace(ssaValue.first); + // Store size of global statements. + m_functionSizes[YulString{}] = CodeSize::codeSize(_ast); map<YulString, size_t> references = ReferencesCounter::countReferences(m_ast); for (auto& statement: m_ast.statements) { @@ -58,7 +60,7 @@ FullInliner::FullInliner(Block& _ast, NameDispenser& _dispenser): m_functions[fun.name] = &fun; // Always inline functions that are only called once. if (references[fun.name] == 1) - m_alwaysInline.emplace(fun.name); + m_singleUse.emplace(fun.name); updateCodeSize(fun); } } @@ -98,7 +100,11 @@ bool FullInliner::shallInline(FunctionCall const& _funCall, YulString _callSite) if (!calledFunction) return false; - if (m_alwaysInline.count(calledFunction->name)) + // Do not inline into already big functions. + if (m_functionSizes.at(_callSite) > 100) + return false; + + if (m_singleUse.count(calledFunction->name)) return true; // Constant arguments might provide a means for further optimization, so they cause a bonus. @@ -114,7 +120,12 @@ bool FullInliner::shallInline(FunctionCall const& _funCall, YulString _callSite) } size_t size = m_functionSizes.at(calledFunction->name); - return (size < 10 || (constantArg && size < 50)); + return (size < 10 || (constantArg && size < 30)); +} + +void FullInliner::tentativelyUpdateCodeSize(YulString _function, YulString _callSite) +{ + m_functionSizes.at(_callSite) += m_functionSizes.at(_function); } @@ -155,6 +166,10 @@ vector<Statement> InlineModifier::performInline(Statement& _statement, FunctionC FunctionDefinition* function = m_driver.function(_funCall.functionName.name); assertThrow(!!function, OptimizerException, "Attempt to inline invalid function."); + m_driver.tentativelyUpdateCodeSize(function->name, m_currentFunction); + + static Expression const zero{Literal{{}, LiteralKind::Number, YulString{"0"}, {}}}; + // helper function to create a new variable that is supposed to model // an existing variable. auto newVariable = [&](TypedName const& _existingVariable, Expression* _value) { @@ -163,6 +178,8 @@ vector<Statement> InlineModifier::performInline(Statement& _statement, FunctionC VariableDeclaration varDecl{_funCall.location, {{_funCall.location, newName, _existingVariable.type}}, {}}; if (_value) varDecl.value = make_shared<Expression>(std::move(*_value)); + else + varDecl.value = make_shared<Expression>(zero); newStatements.emplace_back(std::move(varDecl)); }; diff --git a/libyul/optimiser/FullInliner.h b/libyul/optimiser/FullInliner.h index 8f6211c8..d2dd3229 100644 --- a/libyul/optimiser/FullInliner.h +++ b/libyul/optimiser/FullInliner.h @@ -85,6 +85,11 @@ public: return nullptr; } + /// Adds the size of _funCall to the size of _callSite. This is just + /// a rough estimate that is done during inlining. The proper size + /// should be determined after inlining is completed. + void tentativelyUpdateCodeSize(YulString _function, YulString _callSite); + private: void updateCodeSize(FunctionDefinition& fun); void handleBlock(YulString _currentFunctionName, Block& _block); @@ -94,7 +99,7 @@ private: Block& m_ast; std::map<YulString, FunctionDefinition*> m_functions; /// Names of functions to always inline. - std::set<YulString> m_alwaysInline; + std::set<YulString> m_singleUse; /// Variables that are constants (used for inlining heuristic) std::set<YulString> m_constants; std::map<YulString, size_t> m_functionSizes; diff --git a/libyul/optimiser/Metrics.cpp b/libyul/optimiser/Metrics.cpp index a5557fb3..8fc9476e 100644 --- a/libyul/optimiser/Metrics.cpp +++ b/libyul/optimiser/Metrics.cpp @@ -48,6 +48,9 @@ size_t CodeSize::codeSize(Block const& _block) void CodeSize::visit(Statement const& _statement) { + if (_statement.type() == typeid(FunctionDefinition)) + return; + ++m_size; ASTWalker::visit(_statement); } diff --git a/libyul/optimiser/Metrics.h b/libyul/optimiser/Metrics.h index ca244600..d26ecbd9 100644 --- a/libyul/optimiser/Metrics.h +++ b/libyul/optimiser/Metrics.h @@ -25,17 +25,17 @@ namespace yul { +/** + * Metric for the size of code. + * More specifically, the number of AST nodes. + * Ignores function definitions while traversing the AST. + * If you want to know the size of a function, you have to invoke this on its body. + */ class CodeSize: public ASTWalker { public: - /// Returns a metric for the code size of an AST element. - /// More specifically, it returns the number of AST nodes. static size_t codeSize(Statement const& _statement); - /// Returns a metric for the code size of an AST element. - /// More specifically, it returns the number of AST nodes. static size_t codeSize(Expression const& _expression); - /// Returns a metric for the code size of an AST element. - /// More specifically, it returns the number of AST nodes. static size_t codeSize(Block const& _block); private: diff --git a/libyul/optimiser/SSAValueTracker.cpp b/libyul/optimiser/SSAValueTracker.cpp index ef96c379..23eb9ec2 100644 --- a/libyul/optimiser/SSAValueTracker.cpp +++ b/libyul/optimiser/SSAValueTracker.cpp @@ -33,13 +33,20 @@ void SSAValueTracker::operator()(Assignment const& _assignment) m_values.erase(var.name); } +void SSAValueTracker::operator()(FunctionDefinition const& _funDef) +{ + for (auto const& var: _funDef.returnVariables) + setValue(var.name, nullptr); + ASTWalker::operator()(_funDef); +} + void SSAValueTracker::operator()(VariableDeclaration const& _varDecl) { - if (_varDecl.variables.size() == 1) - setValue(_varDecl.variables.front().name, _varDecl.value.get()); - else if (!_varDecl.value) + if (!_varDecl.value) for (auto const& var: _varDecl.variables) setValue(var.name, nullptr); + else if (_varDecl.variables.size() == 1) + setValue(_varDecl.variables.front().name, _varDecl.value.get()); } void SSAValueTracker::setValue(YulString _name, Expression const* _value) @@ -49,5 +56,8 @@ void SSAValueTracker::setValue(YulString _name, Expression const* _value) OptimizerException, "Source needs to be disambiguated." ); + static Expression const zero{Literal{{}, LiteralKind::Number, YulString{"0"}, {}}}; + if (!_value) + _value = &zero; m_values[_name] = _value; } diff --git a/libyul/optimiser/SSAValueTracker.h b/libyul/optimiser/SSAValueTracker.h index efec2200..0680485f 100644 --- a/libyul/optimiser/SSAValueTracker.h +++ b/libyul/optimiser/SSAValueTracker.h @@ -33,7 +33,7 @@ namespace yul * Class that walks the AST and stores the initial value of each variable * that is never assigned to. * - * Default value is represented as nullptr. + * A special zero constant expression is used for the default value of variables. * * Prerequisite: Disambiguator */ @@ -41,6 +41,7 @@ class SSAValueTracker: public ASTWalker { public: using ASTWalker::operator(); + void operator()(FunctionDefinition const& _funDef) override; void operator()(VariableDeclaration const& _varDecl) override; void operator()(Assignment const& _assignment) override; diff --git a/libyul/optimiser/Suite.cpp b/libyul/optimiser/Suite.cpp index ad22bfa3..bfba8dfc 100644 --- a/libyul/optimiser/Suite.cpp +++ b/libyul/optimiser/Suite.cpp @@ -21,6 +21,7 @@ #include <libyul/optimiser/Suite.h> #include <libyul/optimiser/Disambiguator.h> +#include <libyul/optimiser/VarDeclInitializer.h> #include <libyul/optimiser/FunctionGrouper.h> #include <libyul/optimiser/FunctionHoister.h> #include <libyul/optimiser/ExpressionSplitter.h> @@ -35,7 +36,6 @@ #include <libyul/optimiser/SSATransform.h> #include <libyul/optimiser/StructuralSimplifier.h> #include <libyul/optimiser/RedundantAssignEliminator.h> -#include <libyul/optimiser/VarDeclPropagator.h> #include <libyul/AsmAnalysisInfo.h> #include <libyul/AsmData.h> #include <libyul/AsmPrinter.h> @@ -56,6 +56,7 @@ void OptimiserSuite::run( Block ast = boost::get<Block>(Disambiguator(_analysisInfo, reservedIdentifiers)(_ast)); + (VarDeclInitializer{})(ast); (FunctionHoister{})(ast); (FunctionGrouper{})(ast); (ForLoopInitRewriter{})(ast); @@ -68,7 +69,6 @@ void OptimiserSuite::run( ExpressionSplitter{dispenser}(ast); SSATransform::run(ast, dispenser); RedundantAssignEliminator::run(ast); - VarDeclPropagator{}(ast); RedundantAssignEliminator::run(ast); CommonSubexpressionEliminator{}(ast); @@ -95,27 +95,22 @@ void OptimiserSuite::run( RedundantAssignEliminator::run(ast); CommonSubexpressionEliminator{}(ast); FullInliner{ast, dispenser}.run(); - VarDeclPropagator{}(ast); SSATransform::run(ast, dispenser); RedundantAssignEliminator::run(ast); - VarDeclPropagator{}(ast); RedundantAssignEliminator::run(ast); ExpressionSimplifier::run(ast); StructuralSimplifier{}(ast); CommonSubexpressionEliminator{}(ast); SSATransform::run(ast, dispenser); RedundantAssignEliminator::run(ast); - VarDeclPropagator{}(ast); RedundantAssignEliminator::run(ast); UnusedPruner::runUntilStabilised(ast, reservedIdentifiers); } ExpressionJoiner::run(ast); - VarDeclPropagator{}(ast); UnusedPruner::runUntilStabilised(ast); ExpressionJoiner::run(ast); UnusedPruner::runUntilStabilised(ast); ExpressionJoiner::run(ast); - VarDeclPropagator{}(ast); UnusedPruner::runUntilStabilised(ast); ExpressionJoiner::run(ast); UnusedPruner::runUntilStabilised(ast); diff --git a/libyul/optimiser/VarDeclInitializer.cpp b/libyul/optimiser/VarDeclInitializer.cpp new file mode 100644 index 00000000..4a26757f --- /dev/null +++ b/libyul/optimiser/VarDeclInitializer.cpp @@ -0,0 +1,56 @@ +/* + 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 <http://www.gnu.org/licenses/>. +*/ + +#include <libyul/optimiser/VarDeclInitializer.h> +#include <libyul/AsmData.h> + +#include <libdevcore/CommonData.h> +#include <libdevcore/Visitor.h> + +using namespace std; +using namespace dev; +using namespace yul; + +void VarDeclInitializer::operator()(Block& _block) +{ + ASTModifier::operator()(_block); + + static Expression const zero{Literal{{}, LiteralKind::Number, YulString{"0"}, {}}}; + + using OptionalStatements = boost::optional<vector<Statement>>; + GenericFallbackReturnsVisitor<OptionalStatements, VariableDeclaration> visitor{ + [](VariableDeclaration& _varDecl) -> OptionalStatements + { + if (_varDecl.value) + return {}; + else if (_varDecl.variables.size() == 1) + { + _varDecl.value = make_shared<Expression>(zero); + return {}; + } + else + { + OptionalStatements ret{vector<Statement>{}}; + langutil::SourceLocation loc{std::move(_varDecl.location)}; + for (auto& var: _varDecl.variables) + ret->push_back(VariableDeclaration{loc, {std::move(var)}, make_shared<Expression>(zero)}); + return ret; + } + } + }; + iterateReplacing(_block.statements, boost::apply_visitor(visitor)); +} diff --git a/libyul/optimiser/VarDeclInitializer.h b/libyul/optimiser/VarDeclInitializer.h new file mode 100644 index 00000000..41d0917c --- /dev/null +++ b/libyul/optimiser/VarDeclInitializer.h @@ -0,0 +1,38 @@ +/* + 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 <http://www.gnu.org/licenses/>. +*/ + +#pragma once + +#include <libyul/AsmDataForward.h> +#include <libyul/optimiser/ASTWalker.h> + +namespace yul +{ + +/** + * Rewrites variable declarations so that all of them are initialized. + * Declarations like ``let x, y`` are split into multiple declaration + * statements. + * Only supports initializing with the zero literal for now. + */ +class VarDeclInitializer: public ASTModifier +{ +public: + void operator()(Block& _block) override; +}; + +} diff --git a/libyul/optimiser/VarDeclPropagator.cpp b/libyul/optimiser/VarDeclPropagator.cpp deleted file mode 100644 index bf974f44..00000000 --- a/libyul/optimiser/VarDeclPropagator.cpp +++ /dev/null @@ -1,126 +0,0 @@ -/* - 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 <http://www.gnu.org/licenses/>. -*/ - -#include <libyul/optimiser/VarDeclPropagator.h> -#include <libyul/AsmData.h> -#include <libdevcore/CommonData.h> -#include <boost/range/algorithm_ext/erase.hpp> -#include <algorithm> -#include <map> - -using namespace std; -using namespace dev; -using namespace yul; - -void VarDeclPropagator::operator()(Block& _block) -{ - map<YulString, TypedName> outerEmptyVarDecls; - map<YulString, TypedName> outerLazyInitializedVarDecls; - swap(m_emptyVarDecls, outerEmptyVarDecls); - swap(m_lazyInitializedVarDecls, outerLazyInitializedVarDecls); - - ASTModifier::operator()(_block); - - iterateReplacing( - _block.statements, - [this](Statement& _stmt) -> boost::optional<vector<Statement>> - { - if (_stmt.type() == typeid(VariableDeclaration)) - { - VariableDeclaration& varDecl = boost::get<VariableDeclaration>(_stmt); - boost::remove_erase_if( - varDecl.variables, - [&](TypedName const& _typedName) { return m_lazyInitializedVarDecls.count(_typedName.name); } - ); - if (varDecl.variables.empty()) - return vector<Statement>{}; - else - return {}; - } - else if (_stmt.type() == typeid(Assignment)) - { - Assignment& assignment = boost::get<Assignment>(_stmt); - if (isFullyLazyInitialized(assignment.variableNames)) - return vector<Statement>{recreateVariableDeclaration(assignment)}; - else - return {}; - } - else - return {}; - } - ); - - swap(m_emptyVarDecls, outerEmptyVarDecls); - swap(m_lazyInitializedVarDecls, outerLazyInitializedVarDecls); -} - -void VarDeclPropagator::operator()(VariableDeclaration& _varDecl) -{ - if (_varDecl.value) - visit(*_varDecl.value); - else - for (TypedName const& typedName: _varDecl.variables) - m_emptyVarDecls[typedName.name] = typedName; -} - -void VarDeclPropagator::operator()(Assignment& _assignment) -{ - visit(*_assignment.value); - - if (allVarNamesUninitialized(_assignment.variableNames)) - for (Identifier const& ident: _assignment.variableNames) - m_lazyInitializedVarDecls[ident.name] = m_emptyVarDecls[ident.name]; - - for (Identifier& name: _assignment.variableNames) - (*this)(name); -} - -void VarDeclPropagator::operator()(Identifier& _ident) -{ - m_emptyVarDecls.erase(_ident.name); -} - -bool VarDeclPropagator::allVarNamesUninitialized(vector<Identifier> const& _variableNames) const -{ - return all_of( - begin(_variableNames), - end(_variableNames), - [&](Identifier const& _ident) -> bool { return m_emptyVarDecls.count(_ident.name); } - ); -} - -bool VarDeclPropagator::isFullyLazyInitialized(vector<Identifier> const& _variableNames) const -{ - return all_of( - begin(_variableNames), - end(_variableNames), - [&](Identifier const& ident) -> bool { return m_lazyInitializedVarDecls.count(ident.name); } - ); -} - -VariableDeclaration VarDeclPropagator::recreateVariableDeclaration(Assignment& _assignment) -{ - TypedNameList variables; - - for (Identifier const& varName: _assignment.variableNames) - { - variables.emplace_back(move(m_lazyInitializedVarDecls.at(varName.name))); - m_lazyInitializedVarDecls.erase(varName.name); - } - - return VariableDeclaration{move(_assignment.location), move(variables), std::move(_assignment.value)}; -} diff --git a/libyul/optimiser/VarDeclPropagator.h b/libyul/optimiser/VarDeclPropagator.h deleted file mode 100644 index 1908c214..00000000 --- a/libyul/optimiser/VarDeclPropagator.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - 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 <http://www.gnu.org/licenses/>. -*/ - -#pragma once - -#include <libyul/AsmDataForward.h> -#include <libyul/optimiser/ASTWalker.h> -#include <libyul/Exceptions.h> -#include <libyul/AsmDataForward.h> -#include <vector> -#include <set> -#include <map> - -namespace yul -{ - -/** - * Rewrites Assignment statements into VariableDeclaration when the assignment's LHS - * variables had no value yet. - * - * It recursively walks through the AST and moves each declaration of variables to - * the first assignment within the same block (if possible).. - */ -class VarDeclPropagator: public ASTModifier -{ -public: - using ASTModifier::operator(); - void operator()(Block& _block) override; - void operator()(VariableDeclaration& _varDecl) override; - void operator()(Assignment& _assignment) override; - void operator()(Identifier& _ident) override; - -private: - bool allVarNamesUninitialized(std::vector<Identifier> const& _variableNames) const; - bool isFullyLazyInitialized(std::vector<Identifier> const& _variableNames) const; - VariableDeclaration recreateVariableDeclaration(Assignment& _assignment); - -private: - /// Holds a list of variables from current Block that have no value assigned yet. - std::map<YulString, TypedName> m_emptyVarDecls; - - /// Holds a list variables (and their TypedName) within the current block. - std::map<YulString, TypedName> m_lazyInitializedVarDecls; -}; - -} |