diff options
-rw-r--r-- | libjulia/optimiser/ASTWalker.cpp | 2 | ||||
-rw-r--r-- | libjulia/optimiser/NameCollector.cpp | 6 | ||||
-rw-r--r-- | libjulia/optimiser/NameCollector.h | 14 | ||||
-rw-r--r-- | libjulia/optimiser/Rematerialiser.cpp | 143 | ||||
-rw-r--r-- | libjulia/optimiser/Rematerialiser.h | 64 |
5 files changed, 228 insertions, 1 deletions
diff --git a/libjulia/optimiser/ASTWalker.cpp b/libjulia/optimiser/ASTWalker.cpp index 6386b29d..03444984 100644 --- a/libjulia/optimiser/ASTWalker.cpp +++ b/libjulia/optimiser/ASTWalker.cpp @@ -86,8 +86,8 @@ void ASTWalker::operator()(ForLoop const& _for) { (*this)(_for.pre); visit(*_for.condition); - (*this)(_for.post); (*this)(_for.body); + (*this)(_for.post); } void ASTWalker::operator()(Block const& _block) diff --git a/libjulia/optimiser/NameCollector.cpp b/libjulia/optimiser/NameCollector.cpp index f94104b7..510ee289 100644 --- a/libjulia/optimiser/NameCollector.cpp +++ b/libjulia/optimiser/NameCollector.cpp @@ -67,3 +67,9 @@ map<string, size_t> ReferencesCounter::countReferences(Expression const& _expres counter.visit(_expression); return counter.references(); } + +void Assignments::operator()(Assignment const& _assignment) +{ + for (auto const& var: _assignment.variableNames) + m_names.insert(var.name); +} diff --git a/libjulia/optimiser/NameCollector.h b/libjulia/optimiser/NameCollector.h index 7fe386f7..2d4a1d4b 100644 --- a/libjulia/optimiser/NameCollector.h +++ b/libjulia/optimiser/NameCollector.h @@ -66,5 +66,19 @@ private: std::map<std::string, size_t> m_references; }; +/** + * Specific AST walker that finds all variables that are assigned to. + */ +class Assignments: public ASTWalker +{ +public: + using ASTWalker::operator (); + virtual void operator()(Assignment const& _assignment) override; + + std::set<std::string> const& names() const { return m_names; } +private: + std::set<std::string> m_names; +}; + } } diff --git a/libjulia/optimiser/Rematerialiser.cpp b/libjulia/optimiser/Rematerialiser.cpp new file mode 100644 index 00000000..ca5f94b0 --- /dev/null +++ b/libjulia/optimiser/Rematerialiser.cpp @@ -0,0 +1,143 @@ +/*( + 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/>. +*/ +/** + * Optimisation stage that replaces variables by their most recently assigned expressions. + */ + +#include <libjulia/optimiser/Rematerialiser.h> + +#include <libjulia/optimiser/ASTCopier.h> +#include <libjulia/optimiser/NameCollector.h> + +#include <libsolidity/inlineasm/AsmData.h> + +#include <libjulia/optimiser/Semantics.h> + +#include <libdevcore/CommonData.h> + +using namespace std; +using namespace dev; +using namespace dev::julia; + +void Rematerialiser::operator()(Assignment& _assignment) +{ + set<string> names; + for (auto const& var: _assignment.variableNames) + names.insert(var.name); + handleAssignment(names, _assignment.value.get()); +} + +void Rematerialiser::operator()(VariableDeclaration& _varDecl) +{ + set<string> names; + for (auto const& var: _varDecl.variables) + names.insert(var.name); + handleAssignment(names, _varDecl.value.get()); +} + +void Rematerialiser::operator()(If& _if) +{ + ASTModifier::operator()(_if); + + Assignments ass; + ass(_if.body); + handleAssignment(ass.names(), nullptr); +} + +void Rematerialiser::operator()(Switch& _switch) +{ + boost::apply_visitor(*this, *_switch.expression); + set<string> assignedVariables; + for (auto& _case: _switch.cases) + { + (*this)(_case.body); + Assignments ass; + ass(_case.body); + assignedVariables += ass.names(); + // This is a little too destructive, we could retain the old replacements. + handleAssignment(ass.names(), nullptr); + } + handleAssignment(assignedVariables, nullptr); +} + +void Rematerialiser::operator()(ForLoop& _for) +{ + (*this)(_for.pre); + + Assignments ass; + ass(_for.body); + ass(_for.post); + handleAssignment(ass.names(), nullptr); + + visit(*_for.condition); + (*this)(_for.body); + (*this)(_for.post); + + handleAssignment(ass.names(), nullptr); +} + +void Rematerialiser::handleAssignment(set<string> const& _variables, Expression* _value) +{ + MovableChecker movableChecker; + if (_value) + { + visit(*_value); + movableChecker.visit(*_value); + } + if (_variables.size() == 1) + { + string const& name = *_variables.begin(); + if (movableChecker.movable() && _value) + // TODO Plus heuristic about size of value + // TODO If _value is null, we could use zero. + m_substitutions[name] = _value; + else + m_substitutions.erase(name); + } + // Disallow substitutions that use a variable that will be reassigned by this assignment. + for (auto const& name: _variables) + for (auto const& ref: m_referencedBy[name]) + m_substitutions.erase(ref); + // Update the fact which variables are referenced by the newly assigned variables + for (auto const& name: _variables) + { + for (auto const& ref: m_references[name]) + m_referencedBy[ref].erase(name); + m_references[name].clear(); + } + auto const& referencedVariables = movableChecker.referencedVariables(); + for (auto const& name: _variables) + { + m_references[name] = referencedVariables; + for (auto const& ref: referencedVariables) + m_referencedBy[ref].insert(name); + } +} + +void Rematerialiser::visit(Expression& _e) +{ + if (_e.type() == typeid(Identifier)) + { + Identifier& identifier = boost::get<Identifier>(_e); + if (m_substitutions.count(identifier.name)) + { + string name = identifier.name; + _e = (ASTCopier{}).translate(*m_substitutions.at(name)); + } + } + ASTModifier::visit(_e); +} diff --git a/libjulia/optimiser/Rematerialiser.h b/libjulia/optimiser/Rematerialiser.h new file mode 100644 index 00000000..f2a3102f --- /dev/null +++ b/libjulia/optimiser/Rematerialiser.h @@ -0,0 +1,64 @@ +/* + 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/>. +*/ +/** + * Optimisation stage that replaces variables by their most recently assigned expressions. + */ + +#pragma once + +#include <libjulia/optimiser/ASTWalker.h> + +#include <string> +#include <map> +#include <set> + +namespace dev +{ +namespace julia +{ + +/** + * Optimisation stage that replaces variables by their most recently assigned expressions. + * + * Prerequisite: Disambiguator + */ +class Rematerialiser: public ASTModifier +{ +public: + using ASTModifier::operator(); + virtual void operator()(Assignment& _assignment) override; + virtual void operator()(VariableDeclaration& _varDecl) override; + virtual void operator()(If& _if) override; + virtual void operator()(Switch& _switch) override; + virtual void operator()(ForLoop&) override; + +protected: + virtual void visit(Expression& _e) override; + +private: + void handleAssignment(std::set<std::string> const& _names, Expression* _value); + + /// Substitutions to be performed, if possible. + std::map<std::string, Expression const*> m_substitutions; + /// m_references[a].contains(b) <=> the current expression assigned to a references b + std::map<std::string, std::set<std::string>> m_references; + /// m_referencedBy[b].contains(a) <=> the current expression assigned to a references b + std::map<std::string, std::set<std::string>> m_referencedBy; +}; + +} +} |