diff --git a/libyul/optimiser/ControlFlowSimplifier.cpp b/libyul/optimiser/ControlFlowSimplifier.cpp index 8af8e6bb0..1640fa1b0 100644 --- a/libyul/optimiser/ControlFlowSimplifier.cpp +++ b/libyul/optimiser/ControlFlowSimplifier.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -38,14 +39,13 @@ namespace ExpressionStatement makeDiscardCall( langutil::SourceLocation const& _location, - Dialect const& _dialect, + BuiltinFunction const& _discardFunction, Expression&& _expression ) { - yulAssert(_dialect.discardFunction(), "No discard function available."); return {_location, FunctionCall{ _location, - Identifier{_location, _dialect.discardFunction()->name}, + Identifier{_location, _discardFunction.name}, {std::move(_expression)} }}; } @@ -74,62 +74,12 @@ void removeEmptyCasesFromSwitch(Switch& _switchStmt) ); } -OptionalStatements reduceNoCaseSwitch(Dialect const& _dialect, Switch& _switchStmt) -{ - yulAssert(_switchStmt.cases.empty(), "Expected no case!"); - if (!_dialect.discardFunction()) - return {}; - - auto loc = locationOf(*_switchStmt.expression); - - return make_vector(makeDiscardCall( - loc, - _dialect, - std::move(*_switchStmt.expression) - )); -} - -OptionalStatements reduceSingleCaseSwitch(Dialect const& _dialect, Switch& _switchStmt) -{ - yulAssert(_switchStmt.cases.size() == 1, "Expected only one case!"); - - auto& switchCase = _switchStmt.cases.front(); - auto loc = locationOf(*_switchStmt.expression); - if (switchCase.value) - { - if (!_dialect.equalityFunction()) - return {}; - return make_vector(If{ - std::move(_switchStmt.location), - make_unique(FunctionCall{ - loc, - Identifier{loc, _dialect.equalityFunction()->name}, - {std::move(*switchCase.value), std::move(*_switchStmt.expression)} - }), - std::move(switchCase.body) - }); - } - else - { - if (!_dialect.discardFunction()) - return {}; - - return make_vector( - makeDiscardCall( - loc, - _dialect, - std::move(*_switchStmt.expression) - ), - std::move(switchCase.body) - ); - } -} - } void ControlFlowSimplifier::run(OptimiserStepContext& _context, Block& _ast) { - ControlFlowSimplifier{_context.dialect}(_ast); + TypeInfo typeInfo(_context.dialect, _ast); + ControlFlowSimplifier{_context.dialect, typeInfo}(_ast); } void ControlFlowSimplifier::operator()(Block& _block) @@ -194,12 +144,12 @@ void ControlFlowSimplifier::simplify(std::vector& _statements) GenericVisitor visitor{ VisitorFallback{}, [&](If& _ifStmt) -> OptionalStatements { - if (_ifStmt.body.statements.empty() && m_dialect.discardFunction()) + if (_ifStmt.body.statements.empty() && m_dialect.discardFunction(m_dialect.boolType)) { OptionalStatements s = vector{}; s->emplace_back(makeDiscardCall( _ifStmt.location, - m_dialect, + *m_dialect.discardFunction(m_dialect.boolType), std::move(*_ifStmt.condition) )); return s; @@ -211,9 +161,9 @@ void ControlFlowSimplifier::simplify(std::vector& _statements) removeEmptyCasesFromSwitch(_switchStmt); if (_switchStmt.cases.empty()) - return reduceNoCaseSwitch(m_dialect, _switchStmt); + return reduceNoCaseSwitch(_switchStmt); else if (_switchStmt.cases.size() == 1) - return reduceSingleCaseSwitch(m_dialect, _switchStmt); + return reduceSingleCaseSwitch(_switchStmt); return {}; } @@ -231,3 +181,58 @@ void ControlFlowSimplifier::simplify(std::vector& _statements) } ); } + +OptionalStatements ControlFlowSimplifier::reduceNoCaseSwitch(Switch& _switchStmt) const +{ + yulAssert(_switchStmt.cases.empty(), "Expected no case!"); + BuiltinFunction const* discardFunction = + m_dialect.discardFunction(m_typeInfo.typeOf(*_switchStmt.expression)); + if (!discardFunction) + return {}; + + auto loc = locationOf(*_switchStmt.expression); + + return make_vector(makeDiscardCall( + loc, + *discardFunction, + std::move(*_switchStmt.expression) + )); +} + +OptionalStatements ControlFlowSimplifier::reduceSingleCaseSwitch(Switch& _switchStmt) const +{ + yulAssert(_switchStmt.cases.size() == 1, "Expected only one case!"); + + auto& switchCase = _switchStmt.cases.front(); + auto loc = locationOf(*_switchStmt.expression); + YulString type = m_typeInfo.typeOf(*_switchStmt.expression); + if (switchCase.value) + { + if (!m_dialect.equalityFunction(type)) + return {}; + return make_vector(If{ + std::move(_switchStmt.location), + make_unique(FunctionCall{ + loc, + Identifier{loc, m_dialect.equalityFunction(type)->name}, + {std::move(*switchCase.value), std::move(*_switchStmt.expression)} + }), + std::move(switchCase.body) + }); + } + else + { + if (!m_dialect.discardFunction(type)) + return {}; + + return make_vector( + makeDiscardCall( + loc, + *m_dialect.discardFunction(type), + std::move(*_switchStmt.expression) + ), + std::move(switchCase.body) + ); + } +} + diff --git a/libyul/optimiser/ControlFlowSimplifier.h b/libyul/optimiser/ControlFlowSimplifier.h index 5713f12a1..f8ea1af1e 100644 --- a/libyul/optimiser/ControlFlowSimplifier.h +++ b/libyul/optimiser/ControlFlowSimplifier.h @@ -23,6 +23,7 @@ namespace solidity::yul { struct Dialect; struct OptimiserStepContext; +class TypeInfo; /** * Simplifies several control-flow structures: @@ -61,11 +62,18 @@ public: void visit(Statement& _st) override; private: - ControlFlowSimplifier(Dialect const& _dialect): m_dialect(_dialect) {} + ControlFlowSimplifier(Dialect const& _dialect, TypeInfo const& _typeInfo): + m_dialect(_dialect), + m_typeInfo(_typeInfo) + {} void simplify(std::vector& _statements); + std::optional> reduceNoCaseSwitch(Switch& _switchStmt) const; + std::optional> reduceSingleCaseSwitch(Switch& _switchStmt) const; + Dialect const& m_dialect; + TypeInfo const& m_typeInfo; size_t m_numBreakStatements = 0; size_t m_numContinueStatements = 0; };