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/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/AsmData.h>
@ -66,9 +70,15 @@ void StackToMemoryMover::run(
);
VariableMemoryOffsetTracker memoryOffsetTracker(_reservedMemory, _memorySlots, _numRequiredSlots);
ForLoopConditionIntoBody::run(_context, _block);
ExpressionSplitter::run(_context, _block);
VariableDeclarationAndAssignmentMover declarationAndAssignmentMover(_context, memoryOffsetTracker);
declarationAndAssignmentMover(_block);
ExpressionJoiner::runUntilStabilized(_context, _block);
ForLoopConditionOutOfBody::run(_context, _block);
IdentifierMover identifierMover(_context, memoryOffsetTracker);
identifierMover(_block);
}
@ -108,18 +118,6 @@ void StackToMemoryMover::VariableDeclarationAndAssignmentMover::operator()(Block
auto const& _variables,
std::unique_ptr<Expression> _value
) -> 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)};
vector<Statement> memoryAssignments;
vector<Statement> variableAssignments;

View File

@ -30,19 +30,9 @@ namespace solidity::yul
/**
* Optimisation stage that moves Yul variables from stack to memory.
* 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:
* 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:
* In variable declarations, variables to be moved are replaced by fresh variables and then moved to memory:
* If b and d are in the map, replace
* let a, b, c, d := f()
* by
@ -52,13 +42,7 @@ namespace solidity::yul
* let c := _3
* let a := _1
*
* Assignments to single variables are replaced by mstore's:
* 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:
* Assignments are split up similarly to multi-variable declarations:
* If b and d are in the map, replace
* a, b, c, d := f()
* by
@ -68,7 +52,8 @@ namespace solidity::yul
* c := _3
* 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,
* the entire function is skipped (no local variables in the function will be moved at all).

View File

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

View File

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