[YulOpt] Implement ForLoopConditionIntoBody

This commit is contained in:
mingchuan 2019-05-18 13:35:36 +08:00
parent 4f3b7b232b
commit a86b00e8d0
No known key found for this signature in database
GPG Key ID: 607CD25FA2D03651
4 changed files with 121 additions and 1 deletions

View File

@ -76,6 +76,8 @@ add_library(yul
optimiser/ExpressionSimplifier.h
optimiser/ExpressionSplitter.cpp
optimiser/ExpressionSplitter.h
optimiser/ForLoopConditionIntoBody.cpp
optimiser/ForLoopConditionIntoBody.h
optimiser/ForLoopInitRewriter.cpp
optimiser/ForLoopInitRewriter.h
optimiser/FullInliner.cpp

View File

@ -0,0 +1,56 @@
/*
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/>.
*/
#include <libyul/optimiser/ForLoopConditionIntoBody.h>
#include <libyul/AsmData.h>
#include <libdevcore/CommonData.h>
using namespace std;
using namespace dev;
using namespace yul;
void ForLoopConditionIntoBody::operator()(ForLoop& _forLoop)
{
if (_forLoop.condition->type() != typeid(Literal))
{
langutil::SourceLocation loc = locationOf(*_forLoop.condition);
_forLoop.body.statements.insert(
_forLoop.body.statements.begin(),
If {
loc,
make_unique<Expression>(
FunctionalInstruction {
loc,
eth::Instruction::ISZERO,
make_vector<Expression>(std::move(*_forLoop.condition))
}
),
Block {loc, make_vector<Statement>(Break{{}})}
}
);
_forLoop.condition = make_unique<Expression>(
Literal {
loc,
LiteralKind::Number,
"1"_yulstring,
{}
}
);
}
ASTModifier::operator()(_forLoop);
}

View File

@ -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/>.
*/
#pragma once
#include <libyul/optimiser/ASTWalker.h>
namespace yul
{
/**
* Rewrites ForLoop by moving iteration condition into the ForLoop body.
* For example, `for {} lt(a, b) {} { mstore(1, 2) }` will become
* `for {} 1 {} { if iszero(lt(a, b)) { break } mstore(1, 2) }`
*
* By moving the iteration check part into the ForLoop body, we can apply expression splitter
* to the condition expression.
*
* This rewritter will skip loops that already have literal constant as iteration condition.
*
* Requirements:
* - The Disambiguator must be run upfront.
* - To avoid unnecessary rewrite, it is recommended to run this rewriter after StructuralSimplifier.
*/
class ForLoopConditionIntoBody: public ASTModifier
{
public:
using ASTModifier::operator();
void operator()(ForLoop& _forLoop) override;
};
}

View File

@ -74,6 +74,22 @@ and F is a list of function definitions such that no function contains a functio
The benefit of this stage is that we always know where the list of function begins.
### For Loop Condition Into Body
This transformation moves the iteration condition of a for-loop into loop body.
We need this transformation because [expression splitter](#expression-splitter) won't
apply to iteration condition expressions (the `C` in the following example).
for { Init... } C { Post... } {
Body...
}
is transformed to
for { Init... } 1 { Post... } {
if iszero(C) { break }
Body...
}
### For Loop Init Rewriter
@ -172,7 +188,8 @@ The above would be transformed into
Note that this transformation does not change the order of opcodes or function calls.
It is not applied to loop conditions, because the loop control flow does not allow
this "outlining" of the inner expressions in all cases.
this "outlining" of the inner expressions in all cases. We can sidestep this limitation by applying
[for loop condition into body](#for-loop-condition-into-body) to move the iteration condition into loop body.
The final program should be in a form such that (with the exception of loop conditions)
function calls cannot appear nested inside expressions