Merge pull request #5222 from ethereum/yul-block-flattener

[WIP] Yul: Introduces a block flattening pass
This commit is contained in:
chriseth 2018-10-15 19:50:10 +02:00 committed by GitHub
commit 8677d9276a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 171 additions and 2 deletions

View File

@ -239,9 +239,10 @@ bool contains(T const& _t, V const& _v)
/// on the current element and after that. The actual replacement takes
/// place at the end, but already visited elements might be invalidated.
/// If nothing is replaced, no copy is performed.
template <class T>
void iterateReplacing(std::vector<T>& _vector, std::function<boost::optional<std::vector<T>>(T&)> _f)
template <typename T, typename F>
void iterateReplacing(std::vector<T>& _vector, const F& _f)
{
// Concept: _f must be Callable, must accept param T&, must return optional<vector<T>>
bool useModified = false;
std::vector<T> modifiedVector;
for (size_t i = 0; i < _vector.size(); ++i)

View File

@ -0,0 +1,41 @@
/*
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/BlockFlattener.h>
#include <libsolidity/inlineasm/AsmData.h>
#include <libdevcore/Visitor.h>
#include <libdevcore/CommonData.h>
#include <functional>
using namespace std;
using namespace dev;
using namespace dev::yul;
void BlockFlattener::operator()(Block& _block)
{
ASTModifier::operator()(_block);
iterateReplacing(
_block.statements,
[](Statement& _s) -> boost::optional<vector<Statement>>
{
if (_s.type() == typeid(Block))
return std::move(boost::get<Block>(_s).statements);
else
return {};
}
);
}

View File

@ -0,0 +1,34 @@
/*
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
{
class BlockFlattener: public ASTModifier
{
public:
using ASTModifier::operator();
void operator()(Block& _block) override;
};
}
}

View File

@ -21,6 +21,7 @@
#include <test/Options.h>
#include <libyul/optimiser/BlockFlattener.h>
#include <libyul/optimiser/Disambiguator.h>
#include <libyul/optimiser/CommonSubexpressionEliminator.h>
#include <libyul/optimiser/NameCollector.h>
@ -93,6 +94,11 @@ bool YulOptimizerTest::run(ostream& _stream, string const& _linePrefix, bool con
if (m_optimizerStep == "disambiguator")
disambiguate();
else if (m_optimizerStep == "blockFlattener")
{
disambiguate();
BlockFlattener{}(*m_ast);
}
else if (m_optimizerStep == "commonSubexpressionEliminator")
{
disambiguate();

View File

@ -0,0 +1,20 @@
{
let _1 := mload(0)
let f_a := mload(1)
let f_r
{
f_a := mload(f_a)
f_r := add(f_a, calldatasize())
}
let z := mload(2)
}
// ----
// blockFlattener
// {
// let _1 := mload(0)
// let f_a := mload(1)
// let f_r
// f_a := mload(f_a)
// f_r := add(f_a, calldatasize())
// let z := mload(2)
// }

View File

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

View File

@ -0,0 +1,20 @@
{
if add(mload(7), sload(mload(3)))
{
let y := add(mload(3), 3)
{
y := add(y, 7)
}
}
let t := add(3, 9)
}
// ----
// blockFlattener
// {
// if add(mload(7), sload(mload(3)))
// {
// let y := add(mload(3), 3)
// y := add(y, 7)
// }
// let t := add(3, 9)
// }

View File

@ -0,0 +1,28 @@
{
let a := 3
let b := 4
{
a := add(b, 3)
let c := 5
{
b := add(b, 4)
{
c := add(a, 5)
}
b := add(a, b)
}
a := add(a, c)
}
}
// ----
// blockFlattener
// {
// let a := 3
// let b := 4
// a := add(b, 3)
// let c := 5
// b := add(b, 4)
// c := add(a, 5)
// b := add(a, b)
// a := add(a, c)
// }