diff options
author | chriseth <chris@ethereum.org> | 2018-02-08 23:50:17 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-02-08 23:50:17 +0800 |
commit | 9b61fb2e99a29ae97f6c29bc7309d70622b73886 (patch) | |
tree | 97445fee1a1124a2296e76c76d20fa379c56409f /libjulia | |
parent | 63fb319db3dd927320d28bec2cbf926350cec01c (diff) | |
parent | 7dd99a62c56e50b3deeccd77588c3a65fe6f7107 (diff) | |
download | dexon-solidity-9b61fb2e99a29ae97f6c29bc7309d70622b73886.tar dexon-solidity-9b61fb2e99a29ae97f6c29bc7309d70622b73886.tar.gz dexon-solidity-9b61fb2e99a29ae97f6c29bc7309d70622b73886.tar.bz2 dexon-solidity-9b61fb2e99a29ae97f6c29bc7309d70622b73886.tar.lz dexon-solidity-9b61fb2e99a29ae97f6c29bc7309d70622b73886.tar.xz dexon-solidity-9b61fb2e99a29ae97f6c29bc7309d70622b73886.tar.zst dexon-solidity-9b61fb2e99a29ae97f6c29bc7309d70622b73886.zip |
Merge pull request #3456 from ethereum/simplifier
Use simplification rules also for IULIA
Diffstat (limited to 'libjulia')
-rw-r--r-- | libjulia/optimiser/ExpressionSimplifier.cpp | 50 | ||||
-rw-r--r-- | libjulia/optimiser/ExpressionSimplifier.h | 45 | ||||
-rw-r--r-- | libjulia/optimiser/README.md | 9 | ||||
-rw-r--r-- | libjulia/optimiser/SimplificationRules.cpp | 182 | ||||
-rw-r--r-- | libjulia/optimiser/SimplificationRules.h | 117 | ||||
-rw-r--r-- | libjulia/optimiser/SyntacticalEquality.cpp | 75 | ||||
-rw-r--r-- | libjulia/optimiser/SyntacticalEquality.h | 50 | ||||
-rw-r--r-- | libjulia/optimiser/Utilities.h | 5 |
8 files changed, 533 insertions, 0 deletions
diff --git a/libjulia/optimiser/ExpressionSimplifier.cpp b/libjulia/optimiser/ExpressionSimplifier.cpp new file mode 100644 index 00000000..3d471cb3 --- /dev/null +++ b/libjulia/optimiser/ExpressionSimplifier.cpp @@ -0,0 +1,50 @@ +/* + 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/>. +*/ +/** + * Optimiser component that uses the simplification rules to simplify expressions. + */ + +#include <libjulia/optimiser/ExpressionSimplifier.h> + +#include <libjulia/optimiser/SimplificationRules.h> +#include <libjulia/optimiser/Semantics.h> + +#include <libsolidity/inlineasm/AsmData.h> + +#include <libsolidity/interface/Exceptions.h> + +#include <libdevcore/CommonData.h> + +using namespace std; +using namespace dev; +using namespace dev::julia; +using namespace dev::solidity; + + +void ExpressionSimplifier::visit(Expression& _expression) +{ + ASTModifier::visit(_expression); + while (auto match = SimplificationRules::findFirstMatch(_expression)) + { + // Do not apply the rule if it removes non-constant parts of the expression. + // TODO: The check could actually be less strict than "movable". + // We only require "Does not cause side-effects". + if (match->removesNonConstants && !MovableChecker(_expression).movable()) + return; + _expression = match->action().toExpression(locationOf(_expression)); + } +} diff --git a/libjulia/optimiser/ExpressionSimplifier.h b/libjulia/optimiser/ExpressionSimplifier.h new file mode 100644 index 00000000..8a9e0e20 --- /dev/null +++ b/libjulia/optimiser/ExpressionSimplifier.h @@ -0,0 +1,45 @@ +/* + 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/>. +*/ +/** + * Optimiser component that uses the simplification rules to simplify expressions. + */ + +#pragma once + +#include <libjulia/ASTDataForward.h> + +#include <libjulia/optimiser/ASTWalker.h> + +namespace dev +{ +namespace julia +{ + +/** + * Applies simplification rules to all expressions. + */ +class ExpressionSimplifier: public ASTModifier +{ +public: + using ASTModifier::operator(); + virtual void visit(Expression& _expression); + +private: +}; + +} +} diff --git a/libjulia/optimiser/README.md b/libjulia/optimiser/README.md index 24ee429c..e7134440 100644 --- a/libjulia/optimiser/README.md +++ b/libjulia/optimiser/README.md @@ -78,3 +78,12 @@ a loop or conditional, the first one is not inside), the first assignment is rem ## Function Unifier + +## Expression Simplifier + +This step can only be applied for the EVM-flavoured dialect of iulia. It applies +simple rules like ``x + 0 == x`` to simplify expressions. + +## Ineffective Statement Remover + +This step removes statements that have no side-effects. diff --git a/libjulia/optimiser/SimplificationRules.cpp b/libjulia/optimiser/SimplificationRules.cpp new file mode 100644 index 00000000..a439caef --- /dev/null +++ b/libjulia/optimiser/SimplificationRules.cpp @@ -0,0 +1,182 @@ +/* + 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/>. +*/ +/** + * Module for applying replacement rules against Expressions. + */ + +#include <libjulia/optimiser/SimplificationRules.h> + +#include <libjulia/optimiser/Utilities.h> +#include <libjulia/optimiser/ASTCopier.h> +#include <libjulia/optimiser/Semantics.h> +#include <libjulia/optimiser/SyntacticalEquality.h> + +#include <libsolidity/inlineasm/AsmData.h> + +#include <libevmasm/RuleList.h> + +using namespace std; +using namespace dev; +using namespace dev::julia; + + +SimplificationRule<Pattern> const* SimplificationRules::findFirstMatch(Expression const& _expr) +{ + if (_expr.type() != typeid(FunctionalInstruction)) + return nullptr; + + static SimplificationRules rules; + + FunctionalInstruction const& instruction = boost::get<FunctionalInstruction const&>(_expr); + for (auto const& rule: rules.m_rules[byte(instruction.instruction)]) + { + rules.resetMatchGroups(); + if (rule.pattern.matches(_expr)) + return &rule; + } + return nullptr; +} + +void SimplificationRules::addRules(vector<SimplificationRule<Pattern>> const& _rules) +{ + for (auto const& r: _rules) + addRule(r); +} + +void SimplificationRules::addRule(SimplificationRule<Pattern> const& _rule) +{ + m_rules[byte(_rule.pattern.instruction())].push_back(_rule); +} + +SimplificationRules::SimplificationRules() +{ + // Multiple occurences of one of these inside one rule must match the same equivalence class. + // Constants. + Pattern A(PatternKind::Constant); + Pattern B(PatternKind::Constant); + Pattern C(PatternKind::Constant); + // Anything. + Pattern X; + Pattern Y; + A.setMatchGroup(1, m_matchGroups); + B.setMatchGroup(2, m_matchGroups); + C.setMatchGroup(3, m_matchGroups); + X.setMatchGroup(4, m_matchGroups); + Y.setMatchGroup(5, m_matchGroups); + + addRules(simplificationRuleList(A, B, C, X, Y)); +} + +Pattern::Pattern(solidity::Instruction _instruction, vector<Pattern> const& _arguments): + m_kind(PatternKind::Operation), + m_instruction(_instruction), + m_arguments(_arguments) +{ +} + +void Pattern::setMatchGroup(unsigned _group, map<unsigned, Expression const*>& _matchGroups) +{ + m_matchGroup = _group; + m_matchGroups = &_matchGroups; +} + +bool Pattern::matches(Expression const& _expr) const +{ + if (m_kind == PatternKind::Constant) + { + if (_expr.type() != typeid(Literal)) + return false; + Literal const& literal = boost::get<Literal const&>(_expr); + if (literal.kind != assembly::LiteralKind::Number) + return false; + if (m_data && *m_data != u256(literal.value)) + return false; + assertThrow(m_arguments.empty(), OptimizerException, ""); + } + else if (m_kind == PatternKind::Operation) + { + if (_expr.type() != typeid(FunctionalInstruction)) + return false; + FunctionalInstruction const& instr = boost::get<FunctionalInstruction const&>(_expr); + if (m_instruction != instr.instruction) + return false; + assertThrow(m_arguments.size() == instr.arguments.size(), OptimizerException, ""); + for (size_t i = 0; i < m_arguments.size(); ++i) + if (!m_arguments[i].matches(instr.arguments.at(i))) + return false; + } + else + { + assertThrow(m_arguments.empty(), OptimizerException, ""); + } + // We support matching multiple expressions that require the same value + // based on identical ASTs, which have to be movable. + if (m_matchGroup) + { + if (m_matchGroups->count(m_matchGroup)) + { + Expression const* firstMatch = (*m_matchGroups)[m_matchGroup]; + assertThrow(firstMatch, OptimizerException, "Match set but to null."); + return + SyntacticalEqualityChecker::equal(*firstMatch, _expr) && + MovableChecker(_expr).movable(); + } + else + (*m_matchGroups)[m_matchGroup] = &_expr; + } + return true; +} + +solidity::Instruction Pattern::instruction() const +{ + assertThrow(m_kind == PatternKind::Operation, OptimizerException, ""); + return m_instruction; +} + +Expression Pattern::toExpression(SourceLocation const& _location) const +{ + if (matchGroup()) + return ASTCopier().translate(matchGroupValue()); + if (m_kind == PatternKind::Constant) + { + assertThrow(m_data, OptimizerException, "No match group and no constant value given."); + return Literal{_location, assembly::LiteralKind::Number, m_data->str(), ""}; + } + else if (m_kind == PatternKind::Operation) + { + vector<Expression> arguments; + for (auto const& arg: m_arguments) + arguments.emplace_back(arg.toExpression(_location)); + return FunctionalInstruction{_location, m_instruction, std::move(arguments)}; + } + assertThrow(false, OptimizerException, "Pattern of kind 'any', but no match group."); +} + +u256 Pattern::d() const +{ + Literal const& literal = boost::get<Literal const&>(matchGroupValue()); + assertThrow(literal.kind == assembly::LiteralKind::Number, OptimizerException, ""); + return u256(literal.value); +} + +Expression const& Pattern::matchGroupValue() const +{ + assertThrow(m_matchGroup > 0, OptimizerException, ""); + assertThrow(!!m_matchGroups, OptimizerException, ""); + assertThrow((*m_matchGroups)[m_matchGroup], OptimizerException, ""); + return *(*m_matchGroups)[m_matchGroup]; +} diff --git a/libjulia/optimiser/SimplificationRules.h b/libjulia/optimiser/SimplificationRules.h new file mode 100644 index 00000000..68b640b1 --- /dev/null +++ b/libjulia/optimiser/SimplificationRules.h @@ -0,0 +1,117 @@ +/* + 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/>. +*/ +/** + * Module for applying replacement rules against Expressions. + */ + +#pragma once + +#include <libevmasm/ExpressionClasses.h> +#include <libevmasm/SimplificationRule.h> + +#include <libjulia/ASTDataForward.h> + +#include <libsolidity/inlineasm/AsmData.h> + +#include <boost/noncopyable.hpp> + +#include <functional> +#include <vector> + +namespace dev +{ +namespace julia +{ + +class Pattern; + +/** + * Container for all simplification rules. + */ +class SimplificationRules: public boost::noncopyable +{ +public: + SimplificationRules(); + + /// @returns a pointer to the first matching pattern and sets the match + /// groups accordingly. + static SimplificationRule<Pattern> const* findFirstMatch(Expression const& _expr); + +private: + void addRules(std::vector<SimplificationRule<Pattern>> const& _rules); + void addRule(SimplificationRule<Pattern> const& _rule); + + void resetMatchGroups() { m_matchGroups.clear(); } + + std::map<unsigned, Expression const*> m_matchGroups; + std::vector<SimplificationRule<Pattern>> m_rules[256]; +}; + +enum class PatternKind +{ + Operation, + Constant, + Any +}; + +/** + * Pattern to match against an expression. + * Also stores matched expressions to retrieve them later, for constructing new expressions using + * ExpressionTemplate. + */ +class Pattern +{ +public: + /// Matches any expression. + Pattern(PatternKind _kind = PatternKind::Any): m_kind(_kind) {} + // Matches a specific constant value. + Pattern(unsigned _value): Pattern(u256(_value)) {} + // Matches a specific constant value. + Pattern(u256 const& _value): m_kind(PatternKind::Constant), m_data(std::make_shared<u256>(_value)) {} + // Matches a given instruction with given arguments + Pattern(solidity::Instruction _instruction, std::vector<Pattern> const& _arguments = {}); + /// Sets this pattern to be part of the match group with the identifier @a _group. + /// Inside one rule, all patterns in the same match group have to match expressions from the + /// same expression equivalence class. + void setMatchGroup(unsigned _group, std::map<unsigned, Expression const*>& _matchGroups); + unsigned matchGroup() const { return m_matchGroup; } + bool matches(Expression const& _expr) const; + + std::vector<Pattern> arguments() const { return m_arguments; } + + /// @returns the data of the matched expression if this pattern is part of a match group. + u256 d() const; + + solidity::Instruction instruction() const; + + /// Turns this pattern into an actual expression. Should only be called + /// for patterns resulting from an action, i.e. with match groups assigned. + Expression toExpression(SourceLocation const& _location) const; + +private: + Expression const& matchGroupValue() const; + + PatternKind m_kind = PatternKind::Any; + solidity::Instruction m_instruction; ///< Only valid if m_kind is Operation + std::shared_ptr<u256> m_data; ///< Only valid if m_kind is Constant + std::vector<Pattern> m_arguments; + unsigned m_matchGroup = 0; + std::map<unsigned, Expression const*>* m_matchGroups = nullptr; +}; + +} +} diff --git a/libjulia/optimiser/SyntacticalEquality.cpp b/libjulia/optimiser/SyntacticalEquality.cpp new file mode 100644 index 00000000..2b90b091 --- /dev/null +++ b/libjulia/optimiser/SyntacticalEquality.cpp @@ -0,0 +1,75 @@ +/*( + 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/>. +*/ +/** + * Component that can compare ASTs for equality on a syntactic basis. + */ + +#include <libjulia/optimiser/SyntacticalEquality.h> + +#include <libsolidity/inlineasm/AsmData.h> +#include <libsolidity/interface/Exceptions.h> + +#include <libdevcore/CommonData.h> + +using namespace std; +using namespace dev; +using namespace dev::julia; + +bool SyntacticalEqualityChecker::equal(Expression const& _e1, Expression const& _e2) +{ + if (_e1.type() != _e2.type()) + return false; + + // TODO This should be replaced by some kind of AST walker as soon as it gets + // more complex. + if (_e1.type() == typeid(FunctionalInstruction)) + { + auto const& e1 = boost::get<FunctionalInstruction>(_e1); + auto const& e2 = boost::get<FunctionalInstruction>(_e2); + return + e1.instruction == e2.instruction && + equalVector(e1.arguments, e2.arguments); + } + else if (_e1.type() == typeid(FunctionCall)) + { + auto const& e1 = boost::get<FunctionCall>(_e1); + auto const& e2 = boost::get<FunctionCall>(_e2); + return + equal(e1.functionName, e2.functionName) && + equalVector(e1.arguments, e2.arguments); + } + else if (_e1.type() == typeid(Identifier)) + return boost::get<Identifier>(_e1).name == boost::get<Identifier>(_e2).name; + else if (_e1.type() == typeid(Literal)) + { + auto const& e1 = boost::get<Literal>(_e1); + auto const& e2 = boost::get<Literal>(_e2); + return e1.kind == e2.kind && e1.value == e2.value && e1.type == e2.type; + } + else + { + solAssert(false, "Invlid expression"); + } + return false; +} + +bool SyntacticalEqualityChecker::equalVector(vector<Expression> const& _e1, vector<Expression> const& _e2) +{ + return _e1.size() == _e2.size() && + std::equal(begin(_e1), end(_e1), begin(_e2), SyntacticalEqualityChecker::equal); + +} diff --git a/libjulia/optimiser/SyntacticalEquality.h b/libjulia/optimiser/SyntacticalEquality.h new file mode 100644 index 00000000..b7c09330 --- /dev/null +++ b/libjulia/optimiser/SyntacticalEquality.h @@ -0,0 +1,50 @@ +/* + 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/>. +*/ +/** + * Component that can compare ASTs for equality on a syntactic basis. + */ + +#pragma once + +#include <libjulia/ASTDataForward.h> + +#include <vector> + +namespace dev +{ +namespace julia +{ + +/** + * Component that can compare ASTs for equality on a syntactic basis. + * Ignores source locations but requires exact matches otherwise. + * + * TODO: Only implemented for Expressions for now. + * A future version might also recognize renamed variables and thus could be used to + * remove duplicate functions. + */ +class SyntacticalEqualityChecker +{ +public: + static bool equal(Expression const& _e1, Expression const& _e2); + +protected: + static bool equalVector(std::vector<Expression> const& _e1, std::vector<Expression> const& _e2); +}; + +} +} diff --git a/libjulia/optimiser/Utilities.h b/libjulia/optimiser/Utilities.h index 88ba3f47..e3b4b087 100644 --- a/libjulia/optimiser/Utilities.h +++ b/libjulia/optimiser/Utilities.h @@ -22,11 +22,16 @@ #include <libjulia/ASTDataForward.h> +#include <libdevcore/Exceptions.h> + namespace dev { namespace julia { +struct IuliaException: virtual Exception {}; +struct OptimizerException: virtual IuliaException {}; + /// Removes statements that are just empty blocks (non-recursive). void removeEmptyBlocks(Block& _block); |