diff --git a/libyul/optimiser/StackToMemoryMover.cpp b/libyul/optimiser/StackToMemoryMover.cpp index 722c7a5b6..d7c93e8b4 100644 --- a/libyul/optimiser/StackToMemoryMover.cpp +++ b/libyul/optimiser/StackToMemoryMover.cpp @@ -16,6 +16,10 @@ */ #include #include +#include +#include +#include +#include #include #include @@ -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 _value ) -> std::vector { - if (_variables.size() == 1) - { - optional 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 memoryAssignments; vector variableAssignments; diff --git a/libyul/optimiser/StackToMemoryMover.h b/libyul/optimiser/StackToMemoryMover.h index c26130b8d..58153bf6d 100644 --- a/libyul/optimiser/StackToMemoryMover.h +++ b/libyul/optimiser/StackToMemoryMover.h @@ -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(, 0) - * respectively, replace - * let a := expr - * by - * mstore(, 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(, 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()``. + * 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()``. * * 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). diff --git a/test/libyul/yulOptimizerTests/fakeStackLimitEvader/connected.yul b/test/libyul/yulOptimizerTests/fakeStackLimitEvader/connected.yul index 82ab48a51..76250d618 100644 --- a/test/libyul/yulOptimizerTests/fakeStackLimitEvader/connected.yul +++ b/test/libyul/yulOptimizerTests/fakeStackLimitEvader/connected.yul @@ -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) } diff --git a/test/libyul/yulOptimizerTests/fakeStackLimitEvader/stub.yul b/test/libyul/yulOptimizerTests/fakeStackLimitEvader/stub.yul index d2fcb116e..37e158ef6 100644 --- a/test/libyul/yulOptimizerTests/fakeStackLimitEvader/stub.yul +++ b/test/libyul/yulOptimizerTests/fakeStackLimitEvader/stub.yul @@ -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