diff options
Diffstat (limited to 'libyul/optimiser/SyntacticalEquality.cpp')
-rw-r--r-- | libyul/optimiser/SyntacticalEquality.cpp | 193 |
1 files changed, 156 insertions, 37 deletions
diff --git a/libyul/optimiser/SyntacticalEquality.cpp b/libyul/optimiser/SyntacticalEquality.cpp index 99ce06e5..ba8cc793 100644 --- a/libyul/optimiser/SyntacticalEquality.cpp +++ b/libyul/optimiser/SyntacticalEquality.cpp @@ -22,6 +22,7 @@ #include <libyul/Exceptions.h> #include <libyul/AsmData.h> +#include <libyul/Utilities.h> #include <libdevcore/CommonData.h> @@ -29,48 +30,166 @@ using namespace std; using namespace dev; using namespace yul; -bool SyntacticalEqualityChecker::equal(Expression const& _e1, Expression const& _e2) +bool SyntacticallyEqual::operator()(Expression const& _lhs, Expression const& _rhs) { - if (_e1.type() != _e2.type()) + return boost::apply_visitor([this](auto&& _lhsExpr, auto&& _rhsExpr) -> bool { + // ``this->`` is redundant, but required to work around a bug present in gcc 6.x. + return this->expressionEqual(_lhsExpr, _rhsExpr); + }, _lhs, _rhs); +} + +bool SyntacticallyEqual::operator()(Statement const& _lhs, Statement const& _rhs) +{ + return boost::apply_visitor([this](auto&& _lhsStmt, auto&& _rhsStmt) -> bool { + // ``this->`` is redundant, but required to work around a bug present in gcc 6.x. + return this->statementEqual(_lhsStmt, _rhsStmt); + }, _lhs, _rhs); +} + +bool SyntacticallyEqual::expressionEqual(FunctionalInstruction const& _lhs, FunctionalInstruction const& _rhs) +{ + return + _lhs.instruction == _rhs.instruction && + containerEqual(_lhs.arguments, _rhs.arguments, [this](Expression const& _lhsExpr, Expression const& _rhsExpr) -> bool { + return (*this)(_lhsExpr, _rhsExpr); + }); +} + +bool SyntacticallyEqual::expressionEqual(FunctionCall const& _lhs, FunctionCall const& _rhs) +{ + return + expressionEqual(_lhs.functionName, _rhs.functionName) && + containerEqual(_lhs.arguments, _rhs.arguments, [this](Expression const& _lhsExpr, Expression const& _rhsExpr) -> bool { + return (*this)(_lhsExpr, _rhsExpr); + }); +} + +bool SyntacticallyEqual::expressionEqual(Identifier const& _lhs, Identifier const& _rhs) +{ + auto lhsIt = m_identifiersLHS.find(_lhs.name); + auto rhsIt = m_identifiersRHS.find(_rhs.name); + return + (lhsIt == m_identifiersLHS.end() && rhsIt == m_identifiersRHS.end() && _lhs.name == _rhs.name) || + (lhsIt != m_identifiersLHS.end() && rhsIt != m_identifiersRHS.end() && lhsIt->second == rhsIt->second); +} +bool SyntacticallyEqual::expressionEqual(Literal const& _lhs, Literal const& _rhs) +{ + if (_lhs.kind != _rhs.kind || _lhs.type != _rhs.type) return false; - // TODO This somehow calls strcmp - WHERE? - - // 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; - } + if (_lhs.kind == LiteralKind::Number) + return valueOfNumberLiteral(_lhs) == valueOfNumberLiteral(_rhs); else - { - assertThrow(false, OptimizerException, "Invalid expression"); - } - return false; + return _lhs.value == _rhs.value; } -bool SyntacticalEqualityChecker::equalVector(vector<Expression> const& _e1, vector<Expression> const& _e2) +bool SyntacticallyEqual::statementEqual(ExpressionStatement const& _lhs, ExpressionStatement const& _rhs) { - return _e1.size() == _e2.size() && - std::equal(begin(_e1), end(_e1), begin(_e2), SyntacticalEqualityChecker::equal); + return (*this)(_lhs.expression, _rhs.expression); +} +bool SyntacticallyEqual::statementEqual(Assignment const& _lhs, Assignment const& _rhs) +{ + return containerEqual( + _lhs.variableNames, + _rhs.variableNames, + [this](Identifier const& _lhsVarName, Identifier const& _rhsVarName) -> bool { + return this->expressionEqual(_lhsVarName, _rhsVarName); + } + ) && (*this)(*_lhs.value, *_rhs.value); +} + +bool SyntacticallyEqual::statementEqual(VariableDeclaration const& _lhs, VariableDeclaration const& _rhs) +{ + // first visit expression, then variable declarations + if (!compareSharedPtr<Expression, &SyntacticallyEqual::operator()>(_lhs.value, _rhs.value)) + return false; + return containerEqual(_lhs.variables, _rhs.variables, [this](TypedName const& _lhsVarName, TypedName const& _rhsVarName) -> bool { + return this->visitDeclaration(_lhsVarName, _rhsVarName); + }); +} +bool SyntacticallyEqual::statementEqual(FunctionDefinition const& _lhs, FunctionDefinition const& _rhs) +{ + auto compare = [this](TypedName const& _lhsVarName, TypedName const& _rhsVarName) -> bool { + return this->visitDeclaration(_lhsVarName, _rhsVarName); + }; + // first visit parameter declarations, then body + if (!containerEqual(_lhs.parameters, _rhs.parameters, compare)) + return false; + if (!containerEqual(_lhs.returnVariables, _rhs.returnVariables, compare)) + return false; + return statementEqual(_lhs.body, _rhs.body); +} + +bool SyntacticallyEqual::statementEqual(If const& _lhs, If const& _rhs) +{ + return + compareSharedPtr<Expression, &SyntacticallyEqual::operator()>(_lhs.condition, _rhs.condition) && + statementEqual(_lhs.body, _rhs.body); +} + +bool SyntacticallyEqual::statementEqual(Switch const& _lhs, Switch const& _rhs) +{ + static auto const sortCasesByValue = [](Case const* _lhsCase, Case const* _rhsCase) -> bool { + return Less<Literal*>{}(_lhsCase->value.get(), _rhsCase->value.get()); + }; + std::set<Case const*, decltype(sortCasesByValue)> lhsCases(sortCasesByValue); + std::set<Case const*, decltype(sortCasesByValue)> rhsCases(sortCasesByValue); + for (auto const& lhsCase: _lhs.cases) + lhsCases.insert(&lhsCase); + for (auto const& rhsCase: _rhs.cases) + rhsCases.insert(&rhsCase); + return + compareSharedPtr<Expression, &SyntacticallyEqual::operator()>(_lhs.expression, _rhs.expression) && + containerEqual(lhsCases, rhsCases, [this](Case const* _lhsCase, Case const* _rhsCase) -> bool { + return this->switchCaseEqual(*_lhsCase, *_rhsCase); + }); +} + + +bool SyntacticallyEqual::switchCaseEqual(Case const& _lhs, Case const& _rhs) +{ + return + compareSharedPtr<Literal, &SyntacticallyEqual::expressionEqual>(_lhs.value, _rhs.value) && + statementEqual(_lhs.body, _rhs.body); +} + +bool SyntacticallyEqual::statementEqual(ForLoop const& _lhs, ForLoop const& _rhs) +{ + return + statementEqual(_lhs.pre, _rhs.pre) && + compareSharedPtr<Expression, &SyntacticallyEqual::operator()>(_lhs.condition, _rhs.condition) && + statementEqual(_lhs.body, _rhs.body) && + statementEqual(_lhs.post, _rhs.post); +} + +bool SyntacticallyEqual::statementEqual(Instruction const&, Instruction const&) +{ + assertThrow(false, OptimizerException, ""); +} + +bool SyntacticallyEqual::statementEqual(Label const&, Label const&) +{ + assertThrow(false, OptimizerException, ""); +} + +bool SyntacticallyEqual::statementEqual(StackAssignment const&, StackAssignment const&) +{ + assertThrow(false, OptimizerException, ""); +} + +bool SyntacticallyEqual::statementEqual(Block const& _lhs, Block const& _rhs) +{ + return containerEqual(_lhs.statements, _rhs.statements, [this](Statement const& _lhsStmt, Statement const& _rhsStmt) -> bool { + return (*this)(_lhsStmt, _rhsStmt); + }); +} + +bool SyntacticallyEqual::visitDeclaration(TypedName const& _lhs, TypedName const& _rhs) +{ + if (_lhs.type != _rhs.type) + return false; + std::size_t id = m_idsUsed++; + m_identifiersLHS[_lhs.name] = id; + m_identifiersRHS[_rhs.name] = id; + return true; } |