Skip to content

Commit

Permalink
Update optimizer docs to include codegen-based optimizer section
Browse files Browse the repository at this point in the history
  • Loading branch information
matheusaaguiar committed Oct 26, 2023
1 parent 28ee5d3 commit 3c09b19
Showing 1 changed file with 62 additions and 5 deletions.
67 changes: 62 additions & 5 deletions docs/internals/optimizer.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@
The Optimizer
*************

The Solidity compiler uses two different optimizer modules: The "old" optimizer
that operates at the opcode level and the "new" optimizer that operates on Yul IR code.
The Solidity compiler uses three different optimizer modules: The "old" optimizer
that operates at the opcode level and two "new" optimizers, one that operates on Yul IR code
and another that removes unnecessary overflow checks of code generation of ``for`` loops.

The opcode-based optimizer applies a set of `simplification rules <https://github.com/ethereum/solidity/blob/develop/libevmasm/RuleList.h>`_
to opcodes. It also combines equal code sets and removes unused code.
Expand All @@ -20,17 +21,21 @@ the function calls. Similarly, if a function is
side-effect free and its result is multiplied by zero, you can remove the function
call completely.

The codegen-based optimizer is a single step that makes the compiler use unchecked
arithmetic when generating code of a ``for`` loop counter variable increment.

Currently, the parameter ``--optimize`` activates the opcode-based optimizer for the
generated bytecode and the Yul optimizer for the Yul code generated internally, for example for ABI coder v2.
One can use ``solc --ir-optimized --optimize`` to produce an
optimized Yul IR for a Solidity source. Similarly, one can use ``solc --strict-assembly --optimize``
for a stand-alone Yul mode.

.. note::
The `peephole optimizer <https://en.wikipedia.org/wiki/Peephole_optimization>`_ is always
enabled by default and can only be turned off via the :ref:`Standard JSON <compiler-api>`.
The `peephole optimizer <https://en.wikipedia.org/wiki/Peephole_optimization>`_ and
the codegen-based optimizer are always enabled by default and can only be turned off
via the :ref:`Standard JSON <compiler-api>`.

You can find more details on both optimizer modules and their optimization steps below.
You can find more details on the optimizer modules and their optimization steps below.

Benefits of Optimizing Solidity Code
====================================
Expand Down Expand Up @@ -1382,3 +1387,55 @@ into
}
The LiteralRematerialiser should be run before this step.

Codegen-Based Optimizer Module
==============================

Currently, the codegen-based optimizer module consists of only one step,
which makes the compiler automatically generate unchecked arithmetic code that
increments the counter variable of a `for` loop. The single step of this module,
which is explained next, avoids wasting gas unnecessarily, by identifying some
conditions that guarantee that the counter variable cannot overflow. This eliminates
the need to use a explicit unchecked arithmetic block inside the loop body to
increment the counter variable

Unchecked Loop Increment
------------------------

Introduced in solidity ``0.8.22``, this optimizer step is concerned with identifying
the conditions under which the code of a ``for`` loop counter can be incremented
without overflow checks.
The optimization is always turned on by default and can only
be turned off by setting the ``simpleCounterForLoopUncheckedIncrement`` flag to
false inside ``settings.optimizer.details`` in Standard JSON input.
It is not possible to disable it using the command-line interface.
This optimization is **only** applied to ``for`` loops which use built-in operators ``<`` in the
condition and (postfix/prefix) ``++`` in the lopp expression with the general form:

.. code-block:: solidity
for (uint i = 0; i < x; ++i) {
// variable i is not modified in the loop body
}
In many cases, the comparison is guaranteed to ensure that the counter variable
never overflows. The precise conditions are listed and explained as follows:

- The loop condition is a comparison of the form ``i < x``, for a local counter variable ``i`` and an expression ``x``.
- The built-in operator ``<`` is necessarily used in the loop condition. User-defined operators are **not** eligible.
- The loop expression is a prefix or postfix increment of the counter variable, i.e, ``i++`` or ``++i``.
- The loop counter is a local declared variable of a built-in integer type.
- The loop counter is **not** modified neither in the body nor in the condition.
- The comparison is performed on the same type of the loop counter, meaning that the type of the right-hand-side expression is implicitly convertible to the type of the counter, such that the latter is not implicitly widened before comparing.

To clarify the last condition, consider the next example:

.. code-block:: solidity
for (uint8 i = 0; i < uint16(1000); i++) {
// ...
}
In this case, the counter ``i`` has its type implicitly converted from ``uint8``
to ``uint16`` before the comparison and the condition is in fact never false, so
the overflow check for the increment cannot be removed.

0 comments on commit 3c09b19

Please sign in to comment.