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/ExpressionSplitter.cpp
|
||||
optimiser/ExpressionSplitter.h
|
||||
optimiser/ForLoopConditionIntoBody.cpp
|
||||
optimiser/ForLoopConditionIntoBody.h
|
||||
optimiser/ForLoopInitRewriter.cpp
|
||||
optimiser/ForLoopInitRewriter.h
|
||||
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.
|
||||
|
||||
### 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
|
||||
|
Loading…
Reference in New Issue
Block a user