aboutsummaryrefslogtreecommitdiffstats
path: root/libyul
diff options
context:
space:
mode:
Diffstat (limited to 'libyul')
-rw-r--r--libyul/AsmPrinter.cpp30
-rw-r--r--libyul/AsmPrinter.h30
-rw-r--r--libyul/CMakeLists.txt2
-rw-r--r--libyul/optimiser/DataFlowAnalyzer.cpp12
-rw-r--r--libyul/optimiser/DataFlowAnalyzer.h2
-rw-r--r--libyul/optimiser/FullInliner.cpp23
-rw-r--r--libyul/optimiser/FullInliner.h7
-rw-r--r--libyul/optimiser/Metrics.cpp3
-rw-r--r--libyul/optimiser/Metrics.h12
-rw-r--r--libyul/optimiser/SSAValueTracker.cpp16
-rw-r--r--libyul/optimiser/SSAValueTracker.h3
-rw-r--r--libyul/optimiser/Suite.cpp9
-rw-r--r--libyul/optimiser/VarDeclInitializer.cpp56
-rw-r--r--libyul/optimiser/VarDeclInitializer.h38
-rw-r--r--libyul/optimiser/VarDeclPropagator.cpp126
-rw-r--r--libyul/optimiser/VarDeclPropagator.h60
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;
-};
-
-}