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: Inline external function calls to ``this``.
* Assembler: Encode the compiler version in the deployed bytecode.
* Yul Optimizer: Simplify single-run ``for`` loops to ``if`` statements.
Bugfixes:

View File

@ -115,9 +115,51 @@ void ControlFlowSimplifier::operator()(Block& _block)
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)
{
GenericFallbackReturnsVisitor<OptionalStatements, If, Switch, ForLoop> const visitor(
GenericFallbackReturnsVisitor<OptionalStatements, If, Switch> const visitor(
[&](If& _ifStmt) -> OptionalStatements {
if (_ifStmt.body.statements.empty())
{
@ -136,9 +178,6 @@ void ControlFlowSimplifier::simplify(std::vector<yul::Statement>& _statements)
else if (_switchStmt.cases.size() == 1)
return reduceSingleCaseSwitch(_switchStmt);
return {};
},
[&](ForLoop&) -> OptionalStatements {
return {};
}
);

View File

@ -38,7 +38,7 @@ namespace yul
* The ControlFlowSimplifier does record the presence or absence of ``break``
* 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.
*/
@ -46,9 +46,17 @@ class ControlFlowSimplifier: public ASTModifier
{
public:
using ASTModifier::operator();
void operator()(Break&) override { ++m_numBreakStatements; }
void operator()(Continue&) override { ++m_numContinueStatements; }
void operator()(Block& _block) override;
void visit(Statement& _st) override;
private:
void simplify(std::vector<Statement>& _statements);
size_t m_numBreakStatements = 0;
size_t m_numContinueStatements = 0;
};
}