Simplify single-run for loops to if statements.

This commit is contained in:
chriseth 2019-05-09 22:34:09 +02:00
parent 99e96c2d66
commit 439a225cee
3 changed files with 53 additions and 5 deletions

View File

@ -10,6 +10,7 @@ Compiler Features:
* SMTChecker: Support ``delete``. * SMTChecker: Support ``delete``.
* SMTChecker: Inline external function calls to ``this``. * SMTChecker: Inline external function calls to ``this``.
* Assembler: Encode the compiler version in the deployed bytecode. * Assembler: Encode the compiler version in the deployed bytecode.
* Yul Optimizer: Simplify single-run ``for`` loops to ``if`` statements.
Bugfixes: Bugfixes:

View File

@ -115,9 +115,51 @@ void ControlFlowSimplifier::operator()(Block& _block)
simplify(_block.statements); simplify(_block.statements);
} }
void ControlFlowSimplifier::visit(Statement& _st)
{
if (_st.type() == typeid(ForLoop))
{
ForLoop& forLoop = boost::get<ForLoop>(_st);
yulAssert(forLoop.pre.statements.empty(), "");
size_t outerBreak = m_numBreakStatements;
size_t outerContinue = m_numContinueStatements;
m_numBreakStatements = 0;
m_numContinueStatements = 0;
ASTModifier::visit(_st);
if (!forLoop.body.statements.empty())
{
bool isTerminating = false;
TerminationFinder::ControlFlow controlFlow = TerminationFinder::controlFlowKind(forLoop.body.statements.back());
if (controlFlow == TerminationFinder::ControlFlow::Break)
{
isTerminating = true;
--m_numBreakStatements;
}
else if (controlFlow == TerminationFinder::ControlFlow::Terminate)
isTerminating = true;
if (isTerminating && m_numContinueStatements == 0 && m_numBreakStatements == 0)
{
If replacement{forLoop.location, std::move(forLoop.condition), std::move(forLoop.body)};
if (controlFlow == TerminationFinder::ControlFlow::Break)
replacement.body.statements.resize(replacement.body.statements.size() - 1);
_st = std::move(replacement);
}
}
m_numBreakStatements = outerBreak;
m_numContinueStatements = outerContinue;
}
else
ASTModifier::visit(_st);
}
void ControlFlowSimplifier::simplify(std::vector<yul::Statement>& _statements) void ControlFlowSimplifier::simplify(std::vector<yul::Statement>& _statements)
{ {
GenericFallbackReturnsVisitor<OptionalStatements, If, Switch, ForLoop> const visitor( GenericFallbackReturnsVisitor<OptionalStatements, If, Switch> const visitor(
[&](If& _ifStmt) -> OptionalStatements { [&](If& _ifStmt) -> OptionalStatements {
if (_ifStmt.body.statements.empty()) if (_ifStmt.body.statements.empty())
{ {
@ -136,9 +178,6 @@ void ControlFlowSimplifier::simplify(std::vector<yul::Statement>& _statements)
else if (_switchStmt.cases.size() == 1) else if (_switchStmt.cases.size() == 1)
return reduceSingleCaseSwitch(_switchStmt); return reduceSingleCaseSwitch(_switchStmt);
return {};
},
[&](ForLoop&) -> OptionalStatements {
return {}; return {};
} }
); );

View File

@ -38,7 +38,7 @@ namespace yul
* The ControlFlowSimplifier does record the presence or absence of ``break`` * The ControlFlowSimplifier does record the presence or absence of ``break``
* and ``continue`` statements during its traversal. * and ``continue`` statements during its traversal.
* *
* Prerequisite: Disambiguator, ForLoopInitRewriter. * Prerequisite: Disambiguator, FunctionHoister, ForLoopInitRewriter.
* *
* Important: Introduces EVM opcodes and thus can only be used on EVM code for now. * Important: Introduces EVM opcodes and thus can only be used on EVM code for now.
*/ */
@ -46,9 +46,17 @@ class ControlFlowSimplifier: public ASTModifier
{ {
public: public:
using ASTModifier::operator(); using ASTModifier::operator();
void operator()(Break&) override { ++m_numBreakStatements; }
void operator()(Continue&) override { ++m_numContinueStatements; }
void operator()(Block& _block) override; void operator()(Block& _block) override;
void visit(Statement& _st) override;
private: private:
void simplify(std::vector<Statement>& _statements); void simplify(std::vector<Statement>& _statements);
size_t m_numBreakStatements = 0;
size_t m_numContinueStatements = 0;
}; };
} }