Use ForLoopConditionIntoBody and Expression splitter as preprocessing in StackToMemoryMover, reversing them afterwards.

This commit is contained in:
Daniel Kirchner 2020-10-06 12:46:33 +02:00
parent b0fa2fb296
commit a59bf01ebd
4 changed files with 61 additions and 76 deletions

View File

@ -16,6 +16,10 @@
*/ */
#include <libyul/optimiser/StackToMemoryMover.h> #include <libyul/optimiser/StackToMemoryMover.h>
#include <libyul/optimiser/NameDispenser.h> #include <libyul/optimiser/NameDispenser.h>
#include <libyul/optimiser/ExpressionSplitter.h>
#include <libyul/optimiser/ExpressionJoiner.h>
#include <libyul/optimiser/ForLoopConditionIntoBody.h>
#include <libyul/optimiser/ForLoopConditionOutOfBody.h>
#include <libyul/backends/evm/EVMDialect.h> #include <libyul/backends/evm/EVMDialect.h>
#include <libyul/AsmData.h> #include <libyul/AsmData.h>
@ -66,9 +70,15 @@ void StackToMemoryMover::run(
); );
VariableMemoryOffsetTracker memoryOffsetTracker(_reservedMemory, _memorySlots, _numRequiredSlots); VariableMemoryOffsetTracker memoryOffsetTracker(_reservedMemory, _memorySlots, _numRequiredSlots);
ForLoopConditionIntoBody::run(_context, _block);
ExpressionSplitter::run(_context, _block);
VariableDeclarationAndAssignmentMover declarationAndAssignmentMover(_context, memoryOffsetTracker); VariableDeclarationAndAssignmentMover declarationAndAssignmentMover(_context, memoryOffsetTracker);
declarationAndAssignmentMover(_block); declarationAndAssignmentMover(_block);
ExpressionJoiner::runUntilStabilized(_context, _block);
ForLoopConditionOutOfBody::run(_context, _block);
IdentifierMover identifierMover(_context, memoryOffsetTracker); IdentifierMover identifierMover(_context, memoryOffsetTracker);
identifierMover(_block); identifierMover(_block);
} }
@ -108,18 +118,6 @@ void StackToMemoryMover::VariableDeclarationAndAssignmentMover::operator()(Block
auto const& _variables, auto const& _variables,
std::unique_ptr<Expression> _value std::unique_ptr<Expression> _value
) -> std::vector<Statement> { ) -> std::vector<Statement> {
if (_variables.size() == 1)
{
optional<YulString> offset = m_memoryOffsetTracker(_variables.front().name);
yulAssert(offset, "");
return generateMemoryStore(
m_context.dialect,
_loc,
*offset,
_value ? *std::move(_value) : Literal{_loc, LiteralKind::Number, "0"_yulstring, {}}
);
}
VariableDeclaration tempDecl{_loc, {}, std::move(_value)}; VariableDeclaration tempDecl{_loc, {}, std::move(_value)};
vector<Statement> memoryAssignments; vector<Statement> memoryAssignments;
vector<Statement> variableAssignments; vector<Statement> variableAssignments;

View File

@ -30,19 +30,9 @@ namespace solidity::yul
/** /**
* Optimisation stage that moves Yul variables from stack to memory. * Optimisation stage that moves Yul variables from stack to memory.
* It takes a map from functions names and variable names to memory offsets. * It takes a map from functions names and variable names to memory offsets.
* It then transforms the AST as follows: * It then transforms the AST as follows (after running ForLoopConditionIntoBody and ExpressionSplitter):
* *
* Single variable declarations are replaced by mstore's as follows: * In variable declarations, variables to be moved are replaced by fresh variables and then moved to memory:
* If a is in the map, replace
* let a
* by
* mstore(<memory offset for a>, 0)
* respectively, replace
* let a := expr
* by
* mstore(<memory offset for a>, expr)
*
* In a multi-variable declaration, variables to be moved are replaced by fresh variables and then moved to memory:
* If b and d are in the map, replace * If b and d are in the map, replace
* let a, b, c, d := f() * let a, b, c, d := f()
* by * by
@ -52,13 +42,7 @@ namespace solidity::yul
* let c := _3 * let c := _3
* let a := _1 * let a := _1
* *
* Assignments to single variables are replaced by mstore's: * Assignments are split up similarly to multi-variable declarations:
* If a is in the map, replace
* a := expr
* by
* mstore(<memory offset for a>, expr)
*
* Assignments to multiple variables are split up similarly to multi-variable declarations:
* If b and d are in the map, replace * If b and d are in the map, replace
* a, b, c, d := f() * a, b, c, d := f()
* by * by
@ -68,7 +52,8 @@ namespace solidity::yul
* c := _3 * c := _3
* a := _1 * a := _1
* *
* Replace all references to a variable ``a`` in the map by ``mload(<memory offset for a>)``. * After that, the ExpressionJoiner and ForLoopConditionOutOfBody transformations are run to reverse the preprocessing
* and then all references to a variable ``a`` in the map are replaced by ``mload(<memory offset for a>)``.
* *
* If a visited function has arguments or return parameters that are contained in the map, * If a visited function has arguments or return parameters that are contained in the map,
* the entire function is skipped (no local variables in the function will be moved at all). * the entire function is skipped (no local variables in the function will be moved at all).

View File

@ -29,31 +29,32 @@
// { // {
// a := 21 // a := 21
// mstore(0x60, 1) // mstore(0x60, 1)
// let b_1, a_2, $c_3 := z() // let b_8, a_9, $c_10 := z()
// mstore(0x60, $c_3) // mstore(0x60, $c_10)
// a := a_2 // a := a_9
// b := b_1 // b := b_8
// } // }
// function f() -> x // function f() -> x
// { // {
// mstore(0x20, 0) // let $x2_11
// mstore(0x20, $x2_11)
// mstore(0x20, 42) // mstore(0x20, 42)
// let $x3_4, $x4_5 := g() // let $x3_13, $x4_14 := g()
// mstore(0x00, $x4_5) // mstore(0x00, $x4_14)
// mstore(0x40, $x3_4) // mstore(0x40, $x3_13)
// x := mul(add(mload(0x20), mload(0x40)), h(mload(0x00))) // x := mul(add(mload(0x20), mload(0x40)), h(mload(0x00)))
// sstore(mload(0x40), mload(0x00)) // sstore(mload(0x40), mload(0x00))
// } // }
// function h(v) -> a_1 // function h(v) -> a_1
// { // {
// let x_2_6, $z_7, y_8 := z() // let x_2_15, $z_16, y_17 := z()
// mstore(0x60, $z_7) // mstore(0x60, $z_16)
// let y := y_8 // let y := y_17
// let x_2 := x_2_6 // let x_2 := x_2_15
// let a_1_9, $z_10, v_11 := z() // let a_1_18, $z_19, v_20 := z()
// mstore(0x60, $z_10) // mstore(0x60, $z_19)
// v := v_11 // v := v_20
// a_1 := a_1_9 // a_1 := a_1_18
// } // }
// function z() -> a_3, b_4, c // function z() -> a_3, b_4, c
// { mstore(0x80, 0) } // { mstore(0x80, 0) }

View File

@ -30,52 +30,53 @@
// mstore(0x40, memoryguard(0x80)) // mstore(0x40, memoryguard(0x80))
// function f() // function f()
// { // {
// mstore(0x40, 0) // let $fx_8
// mstore(0x40, $fx_8)
// mstore(0x60, 42) // mstore(0x60, 42)
// sstore(mload(0x40), mload(0x60)) // sstore(mload(0x40), mload(0x60))
// mstore(0x40, 21) // mstore(0x40, 21)
// } // }
// function g(gx) // function g(gx)
// { // {
// let $gx_1, $gy_2 := tuple2() // let $gx_11, $gy_12 := tuple2()
// mstore(0x40, $gy_2) // mstore(0x40, $gy_12)
// mstore(0x60, $gx_1) // mstore(0x60, $gx_11)
// { // {
// let $gx_3, $gy_4 := tuple2() // let $gx_13, $gy_14 := tuple2()
// mstore(0x40, $gy_4) // mstore(0x40, $gy_14)
// mstore(0x60, $gx_3) // mstore(0x60, $gx_13)
// } // }
// { // {
// let $gx_5, gx_6 := tuple2() // let $gx_15, gx_16 := tuple2()
// mstore(0x60, $gx_5) // mstore(0x60, $gx_15)
// gx := gx_6 // gx := gx_16
// } // }
// { // {
// let gx_7, $gy_8 := tuple2() // let gx_17, $gy_18 := tuple2()
// mstore(0x40, $gy_8) // mstore(0x40, $gy_18)
// gx := gx_7 // gx := gx_17
// } // }
// } // }
// function h(hx, hy, hz, hw) // function h(hx, hy, hz, hw)
// { // {
// let $hx_9, $hy_10, $hz_11, $hw_12 := tuple4() // let $hx_19, $hy_20, $hz_21, $hw_22 := tuple4()
// mstore(0x00, $hw_12) // mstore(0x00, $hw_22)
// mstore(0x60, $hz_11) // mstore(0x60, $hz_21)
// mstore(0x40, $hy_10) // mstore(0x40, $hy_20)
// mstore(0x20, $hx_9) // mstore(0x20, $hx_19)
// { // {
// let hx_13, $hy_14, hz_15, $hw_16 := tuple4() // let hx_23, $hy_24, hz_25, $hw_26 := tuple4()
// mstore(0x00, $hw_16) // mstore(0x00, $hw_26)
// mstore(0x40, $hy_14) // mstore(0x40, $hy_24)
// hz := hz_15 // hz := hz_25
// hx := hx_13 // hx := hx_23
// } // }
// { // {
// let $hx_17, $hy_18, hz_19, hw_20 := tuple4() // let $hx_27, $hy_28, hz_29, hw_30 := tuple4()
// mstore(0x40, $hy_18) // mstore(0x40, $hy_28)
// mstore(0x20, $hx_17) // mstore(0x20, $hx_27)
// hw := hw_20 // hw := hw_30
// hz := hz_19 // hz := hz_29
// } // }
// } // }
// function tuple2() -> a, b // function tuple2() -> a, b