Skip to content

Commit b205fe8

Browse files
authored
Merge pull request #13501 from ethereum/document-unused-store-eliminator
Document UnusedStoreEliminator
2 parents db86a73 + 9e505bd commit b205fe8

File tree

2 files changed

+57
-3
lines changed

2 files changed

+57
-3
lines changed

docs/internals/optimizer.rst

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,7 @@ Abbreviation Full name
322322
``a`` :ref:`SSA-transform`
323323
``t`` :ref:`structural-simplifier`
324324
``p`` :ref:`unused-function-parameter-pruner`
325+
``S`` :ref:`unused-store-eliminator`
325326
``u`` :ref:`unused-pruner`
326327
``d`` :ref:`var-decl-initializer`
327328
============ ===============================
@@ -958,7 +959,7 @@ DeadCodeEliminator
958959
This optimization stage removes unreachable code.
959960

960961
Unreachable code is any code within a block which is preceded by a
961-
leave, return, invalid, break, continue, selfdestruct or revert.
962+
leave, return, invalid, break, continue, selfdestruct, revert or by a call to a user-defined function that recurses infinitely.
962963

963964
Function definitions are retained as they might be called by earlier
964965
code and thus are considered reachable.
@@ -1121,6 +1122,52 @@ The step LiteralRematerialiser is not required for correctness. It helps deal wi
11211122
``function f(x) -> y { revert(y, y} }`` where the literal ``y`` will be replaced by its value ``0``,
11221123
allowing us to rewrite the function.
11231124

1125+
.. index:: ! unused store eliminator
1126+
.. _unused-store-eliminator:
1127+
1128+
UnusedStoreEliminator
1129+
^^^^^^^^^^^^^^^^^^^^^
1130+
1131+
Optimizer component that removes redundant ``sstore`` and memory store statements.
1132+
In case of an ``sstore``, if all outgoing code paths revert (due to an explicit ``revert()``, ``invalid()``, or infinite recursion) or
1133+
lead to another ``sstore`` for which the optimizer can tell that it will overwrite the first store, the statement will be removed.
1134+
However, if there is a read operation between the initial ``sstore`` and the revert, or the overwriting ``sstore``, the statement
1135+
will not be removed.
1136+
Such read operations include: external calls, user-defined functions with any storage access, and ``sload`` of a slot that cannot be
1137+
proven to differ from the slot written by the initial ``sstore``.
1138+
1139+
For example, the following code
1140+
1141+
.. code-block:: yul
1142+
1143+
{
1144+
let c := calldataload(0)
1145+
sstore(c, 1)
1146+
if c {
1147+
sstore(c, 2)
1148+
}
1149+
sstore(c, 3)
1150+
}
1151+
1152+
will be transformed into the code below after the Unused Store Eliminator step is run
1153+
1154+
.. code-block:: yul
1155+
1156+
{
1157+
let c := calldataload(0)
1158+
if c { }
1159+
sstore(c, 3)
1160+
}
1161+
1162+
For memory store operations, things are generally simpler, at least in the outermost yul block as all such
1163+
statements will be removed if they are never read from in any code path.
1164+
At function analysis level, however, the approach is similar to ``sstore``, as we do not know whether the memory location will
1165+
be read once we leave the function's scope, so the statement will be removed only if all code code paths lead to a memory overwrite.
1166+
1167+
Best run in SSA form.
1168+
1169+
Prerequisites: Disambiguator, ForLoopInitRewriter.
1170+
11241171
.. _equivalent-function-combiner:
11251172

11261173
EquivalentFunctionCombiner

libyul/optimiser/UnusedStoreEliminator.h

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,15 @@ struct Dialect;
3939
struct AssignedValue;
4040

4141
/**
42-
* Optimizer component that removes sstore statements if they
43-
* are overwritten in all code paths or never read from.
42+
* Optimizer component that removes sstore and memory store statements if conditions are met for their removal.
43+
* In case of an sstore, if all outgoing code paths revert (due to an explicit revert(), invalid(),
44+
* or infinite recursion) or lead to another ``sstore`` for which the optimizer can tell that it will overwrite the first store,
45+
* the statement will be removed.
46+
*
47+
* For memory store operations, things are generally simpler, at least in the outermost yul block as all such statements
48+
* will be removed if they are never read from in any code path. At function analysis level however, the approach is similar
49+
* to sstore, as we don't know whether the memory location will be read once we leave the function's scope,
50+
* so the statement will be removed only if all code code paths lead to a memory overwrite.
4451
*
4552
* The m_store member of UnusedStoreBase is only used with the empty yul string
4653
* as key in the first dimension.

0 commit comments

Comments
 (0)