Skip to content

Commit

Permalink
Merge pull request ethereum#12262 from ethereum/functionGrouper
Browse files Browse the repository at this point in the history
Keep canonical form of Yul during optimization.
  • Loading branch information
chriseth authored Nov 10, 2021
2 parents 19159b9 + 1061818 commit f42e3c0
Show file tree
Hide file tree
Showing 169 changed files with 936 additions and 652 deletions.
20 changes: 13 additions & 7 deletions docs/internals/optimizer.rst
Original file line number Diff line number Diff line change
Expand Up @@ -972,15 +972,19 @@ BlockFlattener
^^^^^^^^^^^^^^

This stage eliminates nested blocks by inserting the statement in the
inner block at the appropriate place in the outer block:
inner block at the appropriate place in the outer block. It depends on the
FunctionGrouper and does not flatten the outermost block to keep the form
produced by the FunctionGrouper.

.. code-block:: yul
{
let x := 2
{
let y := 3
mstore(x, y)
let x := 2
{
let y := 3
mstore(x, y)
}
}
}
Expand All @@ -989,9 +993,11 @@ is transformed to
.. code-block:: yul
{
let x := 2
let y := 3
mstore(x, y)
{
let x := 2
let y := 3
mstore(x, y)
}
}
As long as the code is disambiguated, this does not cause a problem because
Expand Down
12 changes: 12 additions & 0 deletions libyul/optimiser/BlockFlattener.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,15 @@ void BlockFlattener::operator()(Block& _block)
}
);
}

void BlockFlattener::run(OptimiserStepContext&, Block& _ast)
{
BlockFlattener flattener;
for (auto& statement: _ast.statements)
if (auto* block = get_if<Block>(&statement))
flattener(*block);
else if (auto* function = get_if<FunctionDefinition>(&statement))
flattener(function->body);
else
yulAssert(false, "BlockFlattener requires the FunctionGrouper.");
}
2 changes: 1 addition & 1 deletion libyul/optimiser/BlockFlattener.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ class BlockFlattener: public ASTModifier
{
public:
static constexpr char const* name{"BlockFlattener"};
static void run(OptimiserStepContext&, Block& _ast) { BlockFlattener{}(_ast); }
static void run(OptimiserStepContext&, Block& _ast);

using ASTModifier::operator();
void operator()(Block& _block) override;
Expand Down
2 changes: 2 additions & 0 deletions libyul/optimiser/CircularReferencesPruner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include <libyul/optimiser/CircularReferencesPruner.h>

#include <libyul/optimiser/CallGraphGenerator.h>
#include <libyul/optimiser/FunctionGrouper.h>
#include <libyul/optimiser/OptimizerUtilities.h>
#include <libyul/AST.h>

Expand All @@ -29,6 +30,7 @@ using namespace solidity::yul;
void CircularReferencesPruner::run(OptimiserStepContext& _context, Block& _ast)
{
CircularReferencesPruner{_context.reservedIdentifiers}(_ast);
FunctionGrouper::run(_context, _ast);
}

void CircularReferencesPruner::operator()(Block& _block)
Expand Down
4 changes: 3 additions & 1 deletion libyul/optimiser/ExpressionJoiner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

#include <libyul/optimiser/ExpressionJoiner.h>

#include <libyul/optimiser/FunctionGrouper.h>
#include <libyul/optimiser/NameCollector.h>
#include <libyul/optimiser/OptimizerUtilities.h>
#include <libyul/Exceptions.h>
Expand All @@ -37,9 +38,10 @@ using namespace std;
using namespace solidity;
using namespace solidity::yul;

void ExpressionJoiner::run(OptimiserStepContext&, Block& _ast)
void ExpressionJoiner::run(OptimiserStepContext& _context, Block& _ast)
{
ExpressionJoiner{_ast}(_ast);
FunctionGrouper::run(_context, _ast);
}


Expand Down
2 changes: 1 addition & 1 deletion libyul/optimiser/FunctionGrouper.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ struct OptimiserStepContext;
* all function definitions.
*
* After this step, a block is of the form
* { { I...} F... }
* { { I... } F... }
* Where I are (non-function-definition) instructions and F are function definitions.
*/
class FunctionGrouper
Expand Down
2 changes: 2 additions & 0 deletions libyul/optimiser/OptimizerUtilities.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ namespace solidity::yul
{

/// Removes statements that are just empty blocks (non-recursive).
/// If this is run on the outermost block, the FunctionGrouper should be run afterwards to keep
/// the canonical form.
void removeEmptyBlocks(Block& _block);

/// Returns true if a given literal can not be used as an identifier.
Expand Down
2 changes: 1 addition & 1 deletion libyul/optimiser/Suite.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ void OptimiserSuite::run(

// Some steps depend on properties ensured by FunctionHoister, BlockFlattener, FunctionGrouper and
// ForLoopInitRewriter. Run them first to be able to run arbitrary sequences safely.
suite.runSequence("hfgo", ast);
suite.runSequence("hgfo", ast);

NameSimplifier::run(suite.m_context, ast);
// Now the user-supplied part
Expand Down
7 changes: 7 additions & 0 deletions libyul/optimiser/UnusedPruner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include <libyul/optimiser/UnusedPruner.h>

#include <libyul/optimiser/CallGraphGenerator.h>
#include <libyul/optimiser/FunctionGrouper.h>
#include <libyul/optimiser/NameCollector.h>
#include <libyul/optimiser/Semantics.h>
#include <libyul/optimiser/OptimizerUtilities.h>
Expand All @@ -33,6 +34,12 @@ using namespace std;
using namespace solidity;
using namespace solidity::yul;

void UnusedPruner::run(OptimiserStepContext& _context, Block& _ast)
{
UnusedPruner::runUntilStabilisedOnFullAST(_context.dialect, _ast, _context.reservedIdentifiers);
FunctionGrouper::run(_context, _ast);
}

UnusedPruner::UnusedPruner(
Dialect const& _dialect,
Block& _ast,
Expand Down
4 changes: 1 addition & 3 deletions libyul/optimiser/UnusedPruner.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,7 @@ class UnusedPruner: public ASTModifier
{
public:
static constexpr char const* name{"UnusedPruner"};
static void run(OptimiserStepContext& _context, Block& _ast) {
UnusedPruner::runUntilStabilisedOnFullAST(_context.dialect, _ast, _context.reservedIdentifiers);
}
static void run(OptimiserStepContext& _context, Block& _ast);


using ASTModifier::operator();
Expand Down
28 changes: 16 additions & 12 deletions test/libyul/yulOptimizerTests/blockFlattener/basic.yul
Original file line number Diff line number Diff line change
@@ -1,21 +1,25 @@
{
let _1 := mload(0)
let f_a := mload(1)
let f_r
{
f_a := mload(f_a)
f_r := add(f_a, calldatasize())
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)
}
let z := mload(2)
}
// ----
// step: 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)
// {
// 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)
// }
// }
12 changes: 8 additions & 4 deletions test/libyul/yulOptimizerTests/blockFlattener/for_stmt.yul
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
{
for { let a := 1 } iszero(eq(a, 10)) { a := add(a, 1) } {
a := add(a, 1)
{
for { let a := 1 } iszero(eq(a, 10)) { a := add(a, 1) } {
a := add(a, 1)
}
}
}
// ----
// step: blockFlattener
//
// {
// for { let a := 1 } iszero(eq(a, 10)) { a := add(a, 1) }
// { a := add(a, 1) }
// {
// for { let a := 1 } iszero(eq(a, 10)) { a := add(a, 1) }
// { a := add(a, 1) }
// }
// }
24 changes: 14 additions & 10 deletions test/libyul/yulOptimizerTests/blockFlattener/if_stmt.yul
Original file line number Diff line number Diff line change
@@ -1,21 +1,25 @@
{
if add(mload(7), sload(mload(3)))
{
let y := add(mload(3), 3)
{
y := add(y, 7)
}
if add(mload(7), sload(mload(3)))
{
let y := add(mload(3), 3)
{
y := add(y, 7)
}
}
let t := add(3, 9)
}
let t := add(3, 9)
}
// ----
// step: blockFlattener
//
// {
// if add(mload(7), sload(mload(3)))
// {
// let y := add(mload(3), 3)
// y := add(y, 7)
// if add(mload(7), sload(mload(3)))
// {
// let y := add(mload(3), 3)
// y := add(y, 7)
// }
// let t := add(3, 9)
// }
// let t := add(3, 9)
// }
38 changes: 21 additions & 17 deletions test/libyul/yulOptimizerTests/blockFlattener/many_nested_blocks.yul
Original file line number Diff line number Diff line change
@@ -1,29 +1,33 @@
{
let a := 3
let b := 4
{
a := add(b, 3)
let c := 5
let a := 3
let b := 4
{
b := add(b, 4)
a := add(b, 3)
let c := 5
{
c := add(a, 5)
}
b := add(a, b)
b := add(b, 4)
{
c := add(a, 5)
}
b := add(a, b)
}
a := add(a, c)
}
a := add(a, c)
}
}
// ----
// step: 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)
// {
// 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)
// }
// }
24 changes: 14 additions & 10 deletions test/libyul/yulOptimizerTests/blockFlattener/switch_stmt.yul
Original file line number Diff line number Diff line change
@@ -1,23 +1,27 @@
{
{
let a := 1
switch calldataload(0)
case 0 { { { mstore(0, 1) } } a := 8 }
default { a := 3 { a := 4 } }
a := 5
}
}
// ----
// step: blockFlattener
//
// {
// let a := 1
// switch calldataload(0)
// case 0 {
// mstore(0, 1)
// a := 8
// {
// let a := 1
// switch calldataload(0)
// case 0 {
// mstore(0, 1)
// a := 8
// }
// default {
// a := 3
// a := 4
// }
// a := 5
// }
// default {
// a := 3
// a := 4
// }
// a := 5
// }
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@
// step: circularReferencesPruner
//
// {
// let a
// a := h()
// {
// let a
// a := h()
// }
// function f() -> x
// { x := g() }
// function g() -> y
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,4 @@
// ----
// step: circularReferencesPruner
//
// { }
// { { } }
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,4 @@
// ----
// step: circularReferencesPruner
//
// { }
// { { } }
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@
// ----
// step: circularReferencesPruner
//
// { }
// { { } }
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
// step: expressionJoiner
//
// {
// if add(mload(7), sload(mload(3))) { let y := add(mload(3), 3) }
// let t := add(3, 9)
// {
// if add(mload(7), sload(mload(3))) { let y := add(mload(3), 3) }
// let t := add(3, 9)
// }
// }
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@
// step: expressionJoiner
//
// {
// let a := mload(3)
// let b := mload(6)
// sstore(mul(add(b, a), mload(2)), 3)
// {
// let a := mload(3)
// let b := mload(6)
// sstore(mul(add(b, a), mload(2)), 3)
// }
// }
Loading

0 comments on commit f42e3c0

Please sign in to comment.