mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #13501 from ethereum/document-unused-store-eliminator
Document UnusedStoreEliminator
This commit is contained in:
commit
b205fe8494
@ -322,6 +322,7 @@ Abbreviation Full name
|
|||||||
``a`` :ref:`SSA-transform`
|
``a`` :ref:`SSA-transform`
|
||||||
``t`` :ref:`structural-simplifier`
|
``t`` :ref:`structural-simplifier`
|
||||||
``p`` :ref:`unused-function-parameter-pruner`
|
``p`` :ref:`unused-function-parameter-pruner`
|
||||||
|
``S`` :ref:`unused-store-eliminator`
|
||||||
``u`` :ref:`unused-pruner`
|
``u`` :ref:`unused-pruner`
|
||||||
``d`` :ref:`var-decl-initializer`
|
``d`` :ref:`var-decl-initializer`
|
||||||
============ ===============================
|
============ ===============================
|
||||||
@ -958,7 +959,7 @@ DeadCodeEliminator
|
|||||||
This optimization stage removes unreachable code.
|
This optimization stage removes unreachable code.
|
||||||
|
|
||||||
Unreachable code is any code within a block which is preceded by a
|
Unreachable code is any code within a block which is preceded by a
|
||||||
leave, return, invalid, break, continue, selfdestruct or revert.
|
leave, return, invalid, break, continue, selfdestruct, revert or by a call to a user-defined function that recurses infinitely.
|
||||||
|
|
||||||
Function definitions are retained as they might be called by earlier
|
Function definitions are retained as they might be called by earlier
|
||||||
code and thus are considered reachable.
|
code and thus are considered reachable.
|
||||||
@ -1121,6 +1122,52 @@ The step LiteralRematerialiser is not required for correctness. It helps deal wi
|
|||||||
``function f(x) -> y { revert(y, y} }`` where the literal ``y`` will be replaced by its value ``0``,
|
``function f(x) -> y { revert(y, y} }`` where the literal ``y`` will be replaced by its value ``0``,
|
||||||
allowing us to rewrite the function.
|
allowing us to rewrite the function.
|
||||||
|
|
||||||
|
.. index:: ! unused store eliminator
|
||||||
|
.. _unused-store-eliminator:
|
||||||
|
|
||||||
|
UnusedStoreEliminator
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
Optimizer component that removes redundant ``sstore`` and memory store statements.
|
||||||
|
In case of an ``sstore``, if all outgoing code paths revert (due to an explicit ``revert()``, ``invalid()``, or infinite recursion) or
|
||||||
|
lead to another ``sstore`` for which the optimizer can tell that it will overwrite the first store, the statement will be removed.
|
||||||
|
However, if there is a read operation between the initial ``sstore`` and the revert, or the overwriting ``sstore``, the statement
|
||||||
|
will not be removed.
|
||||||
|
Such read operations include: external calls, user-defined functions with any storage access, and ``sload`` of a slot that cannot be
|
||||||
|
proven to differ from the slot written by the initial ``sstore``.
|
||||||
|
|
||||||
|
For example, the following code
|
||||||
|
|
||||||
|
.. code-block:: yul
|
||||||
|
|
||||||
|
{
|
||||||
|
let c := calldataload(0)
|
||||||
|
sstore(c, 1)
|
||||||
|
if c {
|
||||||
|
sstore(c, 2)
|
||||||
|
}
|
||||||
|
sstore(c, 3)
|
||||||
|
}
|
||||||
|
|
||||||
|
will be transformed into the code below after the Unused Store Eliminator step is run
|
||||||
|
|
||||||
|
.. code-block:: yul
|
||||||
|
|
||||||
|
{
|
||||||
|
let c := calldataload(0)
|
||||||
|
if c { }
|
||||||
|
sstore(c, 3)
|
||||||
|
}
|
||||||
|
|
||||||
|
For memory store operations, things are generally simpler, at least in the outermost yul block as all such
|
||||||
|
statements will be removed if they are never read from in any code path.
|
||||||
|
At function analysis level, however, the approach is similar to ``sstore``, as we do not know whether the memory location will
|
||||||
|
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.
|
||||||
|
|
||||||
|
Best run in SSA form.
|
||||||
|
|
||||||
|
Prerequisites: Disambiguator, ForLoopInitRewriter.
|
||||||
|
|
||||||
.. _equivalent-function-combiner:
|
.. _equivalent-function-combiner:
|
||||||
|
|
||||||
EquivalentFunctionCombiner
|
EquivalentFunctionCombiner
|
||||||
|
@ -39,8 +39,15 @@ struct Dialect;
|
|||||||
struct AssignedValue;
|
struct AssignedValue;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Optimizer component that removes sstore statements if they
|
* Optimizer component that removes sstore and memory store statements if conditions are met for their removal.
|
||||||
* are overwritten in all code paths or never read from.
|
* In case of an sstore, if all outgoing code paths revert (due to an explicit revert(), invalid(),
|
||||||
|
* or infinite recursion) or lead to another ``sstore`` for which the optimizer can tell that it will overwrite the first store,
|
||||||
|
* the statement will be removed.
|
||||||
|
*
|
||||||
|
* For memory store operations, things are generally simpler, at least in the outermost yul block as all such statements
|
||||||
|
* will be removed if they are never read from in any code path. At function analysis level however, the approach is similar
|
||||||
|
* to sstore, as we don't know whether the memory location will 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.
|
||||||
*
|
*
|
||||||
* The m_store member of UnusedStoreBase is only used with the empty yul string
|
* The m_store member of UnusedStoreBase is only used with the empty yul string
|
||||||
* as key in the first dimension.
|
* as key in the first dimension.
|
||||||
|
Loading…
Reference in New Issue
Block a user