mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
[YulOpt] Implement ForLoopConditionIntoBody
This commit is contained in:
parent
4f3b7b232b
commit
a86b00e8d0
@ -76,6 +76,8 @@ add_library(yul
|
|||||||
optimiser/ExpressionSimplifier.h
|
optimiser/ExpressionSimplifier.h
|
||||||
optimiser/ExpressionSplitter.cpp
|
optimiser/ExpressionSplitter.cpp
|
||||||
optimiser/ExpressionSplitter.h
|
optimiser/ExpressionSplitter.h
|
||||||
|
optimiser/ForLoopConditionIntoBody.cpp
|
||||||
|
optimiser/ForLoopConditionIntoBody.h
|
||||||
optimiser/ForLoopInitRewriter.cpp
|
optimiser/ForLoopInitRewriter.cpp
|
||||||
optimiser/ForLoopInitRewriter.h
|
optimiser/ForLoopInitRewriter.h
|
||||||
optimiser/FullInliner.cpp
|
optimiser/FullInliner.cpp
|
||||||
|
56
libyul/optimiser/ForLoopConditionIntoBody.cpp
Normal file
56
libyul/optimiser/ForLoopConditionIntoBody.cpp
Normal 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);
|
||||||
|
}
|
||||||
|
|
45
libyul/optimiser/ForLoopConditionIntoBody.h
Normal file
45
libyul/optimiser/ForLoopConditionIntoBody.h
Normal 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;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
@ -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.
|
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
|
### 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.
|
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
|
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)
|
The final program should be in a form such that (with the exception of loop conditions)
|
||||||
function calls cannot appear nested inside expressions
|
function calls cannot appear nested inside expressions
|
||||||
|
Loading…
Reference in New Issue
Block a user