Merge pull request #5355 from ethereum/yul-forloop-pre-rewrite

[Yul] Implements a pass to rewrite for-loop's pre block into the parent's Block
This commit is contained in:
chriseth 2018-11-21 16:10:52 +01:00 committed by GitHub
commit 8e98885c53
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 159 additions and 1 deletions

View File

@ -0,0 +1,43 @@
/*
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/ForLoopInitRewriter.h>
#include <libsolidity/inlineasm/AsmData.h>
#include <libdevcore/CommonData.h>
#include <functional>
using namespace std;
using namespace dev;
using namespace dev::yul;
void ForLoopInitRewriter::operator()(Block& _block)
{
iterateReplacing(
_block.statements,
[](Statement& _stmt) -> boost::optional<vector<Statement>>
{
if (_stmt.type() == typeid(ForLoop))
{
auto& forLoop = boost::get<ForLoop>(_stmt);
vector<Statement> rewrite;
swap(rewrite, forLoop.pre.statements);
rewrite.emplace_back(move(forLoop));
return rewrite;
}
return {};
}
);
}

View File

@ -0,0 +1,39 @@
/*
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 dev
{
namespace yul
{
/**
* Rewrites ForLoop by moving the pre statement block in front of the ForLoop.
* Requirements:
* - The Disambiguator must be run upfront.
*/
class ForLoopInitRewriter: public ASTModifier
{
public:
using ASTModifier::operator();
void operator()(Block& _block) override;
};
}
}

View File

@ -27,6 +27,7 @@
#include <libyul/optimiser/ExpressionJoiner.h> #include <libyul/optimiser/ExpressionJoiner.h>
#include <libyul/optimiser/ExpressionInliner.h> #include <libyul/optimiser/ExpressionInliner.h>
#include <libyul/optimiser/FullInliner.h> #include <libyul/optimiser/FullInliner.h>
#include <libyul/optimiser/ForLoopInitRewriter.h>
#include <libyul/optimiser/Rematerialiser.h> #include <libyul/optimiser/Rematerialiser.h>
#include <libyul/optimiser/UnusedPruner.h> #include <libyul/optimiser/UnusedPruner.h>
#include <libyul/optimiser/ExpressionSimplifier.h> #include <libyul/optimiser/ExpressionSimplifier.h>
@ -58,6 +59,7 @@ void OptimiserSuite::run(
(FunctionHoister{})(ast); (FunctionHoister{})(ast);
(FunctionGrouper{})(ast); (FunctionGrouper{})(ast);
(ForLoopInitRewriter{})(ast);
NameDispenser dispenser{ast}; NameDispenser dispenser{ast};

View File

@ -31,6 +31,7 @@
#include <libyul/optimiser/FunctionHoister.h> #include <libyul/optimiser/FunctionHoister.h>
#include <libyul/optimiser/ExpressionInliner.h> #include <libyul/optimiser/ExpressionInliner.h>
#include <libyul/optimiser/FullInliner.h> #include <libyul/optimiser/FullInliner.h>
#include <libyul/optimiser/ForLoopInitRewriter.h>
#include <libyul/optimiser/MainFunction.h> #include <libyul/optimiser/MainFunction.h>
#include <libyul/optimiser/Rematerialiser.h> #include <libyul/optimiser/Rematerialiser.h>
#include <libyul/optimiser/ExpressionSimplifier.h> #include <libyul/optimiser/ExpressionSimplifier.h>
@ -108,6 +109,11 @@ bool YulOptimizerTest::run(ostream& _stream, string const& _linePrefix, bool con
disambiguate(); disambiguate();
VarDeclPropagator{}(*m_ast); VarDeclPropagator{}(*m_ast);
} }
else if (m_optimizerStep == "forLoopInitRewriter")
{
disambiguate();
ForLoopInitRewriter{}(*m_ast);
}
else if (m_optimizerStep == "commonSubexpressionEliminator") else if (m_optimizerStep == "commonSubexpressionEliminator")
{ {
disambiguate(); disambiguate();

View File

@ -0,0 +1,23 @@
{
let random := 42
for { let a := 1
let b := 1 } iszero(eq(a, 10)) { a := add(a, b) } {
a := add(a, 1)
}
}
// ----
// forLoopInitRewriter
// {
// let random := 42
// let a := 1
// let b := 1
// for {
// }
// iszero(eq(a, 10))
// {
// a := add(a, b)
// }
// {
// a := add(a, 1)
// }
// }

View File

@ -0,0 +1,20 @@
{
let a := 1
for {} iszero(eq(a, 10)) { a := add(a, 1) } {
a := add(a, 1)
}
}
// ----
// forLoopInitRewriter
// {
// let a := 1
// for {
// }
// iszero(eq(a, 10))
// {
// a := add(a, 1)
// }
// {
// a := add(a, 1)
// }
// }

View File

@ -0,0 +1,21 @@
{
let random := 42
for { let a := 1 } iszero(eq(a, 10)) { a := add(a, 1) } {
a := add(a, 1)
}
}
// ----
// forLoopInitRewriter
// {
// let random := 42
// let a := 1
// for {
// }
// iszero(eq(a, 10))
// {
// a := add(a, 1)
// }
// {
// a := add(a, 1)
// }
// }

View File

@ -38,6 +38,7 @@
#include <libyul/optimiser/FunctionHoister.h> #include <libyul/optimiser/FunctionHoister.h>
#include <libyul/optimiser/ExpressionInliner.h> #include <libyul/optimiser/ExpressionInliner.h>
#include <libyul/optimiser/FullInliner.h> #include <libyul/optimiser/FullInliner.h>
#include <libyul/optimiser/ForLoopInitRewriter.h>
#include <libyul/optimiser/MainFunction.h> #include <libyul/optimiser/MainFunction.h>
#include <libyul/optimiser/Rematerialiser.h> #include <libyul/optimiser/Rematerialiser.h>
#include <libyul/optimiser/ExpressionSimplifier.h> #include <libyul/optimiser/ExpressionSimplifier.h>
@ -123,7 +124,7 @@ public:
} }
cout << "(q)quit/(f)flatten/(c)se/propagate var(d)ecls/(x)plit/(j)oin/(g)rouper/(h)oister/" << endl; cout << "(q)quit/(f)flatten/(c)se/propagate var(d)ecls/(x)plit/(j)oin/(g)rouper/(h)oister/" << endl;
cout << " (e)xpr inline/(i)nline/(s)implify/(u)nusedprune/ss(a) transform/" << endl; cout << " (e)xpr inline/(i)nline/(s)implify/(u)nusedprune/ss(a) transform/" << endl;
cout << " (r)edundant assign elim./re(m)aterializer? "; cout << " (r)edundant assign elim./re(m)aterializer/f(o)r-loop-pre-rewriter? ";
cout.flush(); cout.flush();
int option = readStandardInputChar(); int option = readStandardInputChar();
cout << ' ' << char(option) << endl; cout << ' ' << char(option) << endl;
@ -134,6 +135,9 @@ public:
case 'f': case 'f':
BlockFlattener{}(*m_ast); BlockFlattener{}(*m_ast);
break; break;
case 'o':
ForLoopInitRewriter{}(*m_ast);
break;
case 'c': case 'c':
(CommonSubexpressionEliminator{})(*m_ast); (CommonSubexpressionEliminator{})(*m_ast);
break; break;