Skip to content

Commit

Permalink
Address review comments
Browse files Browse the repository at this point in the history
  • Loading branch information
nikola-matic committed Sep 13, 2022
1 parent feba1bf commit e37dc8e
Show file tree
Hide file tree
Showing 23 changed files with 108 additions and 243 deletions.
5 changes: 3 additions & 2 deletions Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ Language Features:


Compiler Features:
* Yul Optimizer: Allow replacing the previously hard-coded cleanup sequence by specifying custom steps after a colon delimiter (`:`) in the sequence string.
* Yul Optimizer: Allow replacing the previously hard-coded cleanup sequence by specifying custom steps after a colon delimiter (``:``) in the sequence string.


Bugfixes:

Expand All @@ -21,7 +22,7 @@ Compiler Features:
* Yul Optimizer: Simplify the starting offset of zero-length operations to zero.


Bugfixes:`````
Bugfixes:
* Type Checker: Fix internal compiler error on tuple assignments with invalid left-hand side.
* Yul IR Code Generation: Fix internal compiler error when accessing the ``.slot`` member of a mapping through a storage reference in inline assembly.

Expand Down
103 changes: 69 additions & 34 deletions docs/internals/optimizer.rst
Original file line number Diff line number Diff line change
Expand Up @@ -281,50 +281,85 @@ The following transformation steps are the main components:
- Redundant Assign Eliminator
- Full Inliner

.. _optimizer-steps:

Optimizer Steps
---------------

This is a list of all steps the Yul-based optimizer sorted alphabetically. You can find more information
on the individual steps and their sequence below.

- :ref:`block-flattener`.
- :ref:`circular-reference-pruner`.
- :ref:`common-subexpression-eliminator`.
- :ref:`conditional-simplifier`.
- :ref:`conditional-unsimplifier`.
- :ref:`control-flow-simplifier`.
- :ref:`dead-code-eliminator`.
- :ref:`equal-store-eliminator`.
- :ref:`equivalent-function-combiner`.
- :ref:`expression-joiner`.
- :ref:`expression-simplifier`.
- :ref:`expression-splitter`.
- :ref:`for-loop-condition-into-body`.
- :ref:`for-loop-condition-out-of-body`.
- :ref:`for-loop-init-rewriter`.
- :ref:`expression-inliner`.
- :ref:`full-inliner`.
- :ref:`function-grouper`.
- :ref:`function-hoister`.
- :ref:`function-specializer`.
- :ref:`literal-rematerialiser`.
- :ref:`load-resolver`.
- :ref:`loop-invariant-code-motion`.
- :ref:`redundant-assign-eliminator`.
- :ref:`reasoning-based-simplifier`.
- :ref:`rematerialiser`.
- :ref:`SSA-reverser`.
- :ref:`SSA-transform`.
- :ref:`structural-simplifier`.
- :ref:`unused-function-parameter-pruner`.
- :ref:`unused-pruner`.
- :ref:`var-decl-initializer`.
============ ===============================
Abbreviation Full name
============ ===============================
``f`` :ref:`block-flattener`
``l`` :ref:`circular-reference-pruner`
``c`` :ref:`common-subexpression-eliminator`
``C`` :ref:`conditional-simplifier`
``U`` :ref:`conditional-unsimplifier`
``n`` :ref:`control-flow-simplifier`
``D`` :ref:`dead-code-eliminator`
``E`` :ref:`equal-store-eliminator`
``v`` :ref:`equivalent-function-combiner`
``e`` :ref:`expression-inliner`
``j`` :ref:`expression-joiner`
``s`` :ref:`expression-simplifier`
``x`` :ref:`expression-splitter`
``I`` :ref:`for-loop-condition-into-body`
``O`` :ref:`for-loop-condition-out-of-body`
``o`` :ref:`for-loop-init-rewriter`
``i`` :ref:`full-inliner`
``g`` :ref:`function-grouper`
``h`` :ref:`function-hoister`
``F`` :ref:`function-specializer`
``T`` :ref:`literal-rematerialiser`
``L`` :ref:`load-resolver`
``M`` :ref:`loop-invariant-code-motion`
``r`` :ref:`redundant-assign-eliminator`
``R`` :ref:`reasoning-based-simplifier` - highly experimental
``m`` :ref:`rematerialiser`
``V`` :ref:`SSA-reverser`
``a`` :ref:`SSA-transform`
``t`` :ref:`structural-simplifier`
``p`` :ref:`unused-function-parameter-pruner`
``u`` :ref:`unused-pruner`
``d`` :ref:`var-decl-initializer`
============ ===============================

Some steps depend on properties ensured by ``BlockFlattener``, ``FunctionGrouper``, ``ForLoopInitRewriter``.
For this reason the Yul optimizer always applies them before applying any steps supplied by the user.

The ReasoningBasedSimplifier is an optimizer step that is currently not enabled
in the default set of steps. It uses an SMT solver to simplify arithmetic expressions
and boolean conditions. It has not received thorough testing or validation yet and can produce
non-reproducible results, so please use with care!

Selecting Optimizations
-----------------------

Detailed information regrading the optimization sequence as well a list of abbreviations is
available in the :ref:`Yul optimizer docs <optimization-step-sequence>`.
By default the optimizer applies its predefined sequence of optimization steps to the generated assembly.
You can override this sequence and supply your own using the ``--yul-optimizations`` option:

.. code-block:: bash
solc --optimize --ir-optimized --yul-optimizations 'dhfoD[xarrscLMcCTU]uljmul:fDnTOc'
The order of steps is significant and affects the quality of the output.
Moreover, applying a step may uncover new optimization opportunities for others that were already applied,
so repeating steps is often beneficial.

The sequence inside ``[...]`` will be applied multiple times in a loop until the Yul code
remains unchanged or until the maximum number of rounds (currently 12) has been reached.
Brackets (``[]``) may be used multiple times in a sequence, but can not be nested.

An important thing to note, is that there are some hardcoded steps that are always run before and after the
user-supplied sequence, or the default sequence if one was not supplied by the user.

The cleanup sequence delimiter ``:`` is optional, and is used to supply a custom cleanup sequence
in order to replace the default one. If omitted, the optimizer will simply apply the default cleanup
sequence. In addition, the delimiter may be placed at the beginning of the user-supplied sequence,
which will result in the optimization sequence being empty, whereas conversely, if placed at the end of
the sequence, will be treated as an empty cleanup sequence.

Preprocessing
-------------
Expand Down
68 changes: 2 additions & 66 deletions docs/yul.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1245,72 +1245,8 @@ In Solidity mode, the Yul optimizer is activated together with the regular optim
Optimization Step Sequence
--------------------------

By default the optimizer applies its predefined sequence of optimization steps to
the generated assembly. You can override this sequence and supply your own using
the ``--yul-optimizations`` option:

.. code-block:: bash
solc --optimize --ir-optimized --yul-optimizations 'dhfoD[xarrscLMcCTU]uljmul:fDnTOc'
The sequence inside ``[...]`` will be applied multiple times in a loop until the Yul code
remains unchanged or until the maximum number of rounds (currently 12) has been reached.

An important thing to note, is that there are hardcoded sequences that are run before and after the
user-supplied sequence, or the default sequence if one was not supplied by the user.

The cleanup sequence delimiter ``:`` is optional, and is used to supply a custom cleanup sequence
in order to replace the default one. If omitted, the optimizer will simply apply the default cleanup
sequence. In addition, the delimiter may be placed at the beginning of the user-supplied sequence,
which will be treated as an empty optimization sequence, whereas conversely, if placed at the end of
the sequence, will be treated as an empty cleanup sequence.


The following optimization steps are available:

============ ===============================
Abbreviation Full name
============ ===============================
``f`` ``BlockFlattener``
``l`` ``CircularReferencesPruner``
``c`` ``CommonSubexpressionEliminator``
``C`` ``ConditionalSimplifier``
``U`` ``ConditionalUnsimplifier``
``n`` ``ControlFlowSimplifier``
``D`` ``DeadCodeEliminator``
``v`` ``EquivalentFunctionCombiner``
``e`` ``ExpressionInliner``
``j`` ``ExpressionJoiner``
``s`` ``ExpressionSimplifier``
``x`` ``ExpressionSplitter``
``I`` ``ForLoopConditionIntoBody``
``O`` ``ForLoopConditionOutOfBody``
``o`` ``ForLoopInitRewriter``
``i`` ``FullInliner``
``g`` ``FunctionGrouper``
``h`` ``FunctionHoister``
``F`` ``FunctionSpecializer``
``T`` ``LiteralRematerialiser``
``L`` ``LoadResolver``
``M`` ``LoopInvariantCodeMotion``
``r`` ``RedundantAssignEliminator``
``R`` ``ReasoningBasedSimplifier`` - highly experimental
``m`` ``Rematerialiser``
``V`` ``SSAReverser``
``a`` ``SSATransform``
``t`` ``StructuralSimplifier``
``u`` ``UnusedPruner``
``p`` ``UnusedFunctionParameterPruner``
``d`` ``VarDeclInitializer``
============ ===============================

Some steps depend on properties ensured by ``BlockFlattener``, ``FunctionGrouper``, ``ForLoopInitRewriter``.
For this reason the Yul optimizer always applies them before applying any steps supplied by the user.

The ReasoningBasedSimplifier is an optimizer step that is currently not enabled
in the default set of steps. It uses an SMT solver to simplify arithmetic expressions
and boolean conditions. It has not received thorough testing or validation yet and can produce
non-reproducible results, so please use with care!
Detailed information regrading the optimization sequence as well a list of abbreviations is
available in the :ref:`optimizer docs <optimizer-steps>`.

.. _erc20yul:

Expand Down
2 changes: 2 additions & 0 deletions libsolidity/interface/StandardCompiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -496,6 +496,8 @@ std::optional<Json::Value> checkOptimizerDetailSteps(Json::Value const& _details

if (delimiterPos != string::npos)
_cleanupSetting = fullSequence.substr(delimiterPos + 1);
else
solAssert(_cleanupSetting == OptimiserSettings::DefaultYulOptimiserCleanupSteps);
}
else
return formatFatalError("JSONError", "\"settings.optimizer.details." + _name + "\" must be a string");
Expand Down
5 changes: 4 additions & 1 deletion libyul/optimiser/Suite.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,9 @@ void OptimiserSuite::run(

// Run the user-supplied clean up sequence
suite.runSequence(_optimisationCleanupSequence, ast);
// Hard-coded FunctionGrouper step is used to bring the AST into a canonical form required by the StackCompressor
// and StackLimitEvader. This is hard-coded as the last step, as some previously executed steps may break the
// aforementioned form, thus causing the StackCompressor/StackLimitEvader to throw.
suite.runSequence("g", ast);

if (evmDialect)
Expand Down Expand Up @@ -318,7 +321,7 @@ void OptimiserSuite::validateSequence(string_view _stepAbbreviations)
case ':':
++colonDelimiters;
assertThrow(nestingLevel == 0, OptimizerException, "Cleanup sequence delimiter cannot be placed inside the brackets");
assertThrow(colonDelimiters <=1, OptimizerException, "Too many cleanup sequence delimiters");
assertThrow(colonDelimiters <= 1, OptimizerException, "Too many cleanup sequence delimiters");
break;
default:
{
Expand Down
2 changes: 2 additions & 0 deletions solc/CommandLineParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,8 @@ OptimiserSettings CommandLineOptions::optimiserSettings() const

if (delimiterPos != string::npos)
settings.yulOptimiserCleanupSteps = fullSequence.substr(delimiterPos + 1);
else
solAssert(settings.yulOptimiserCleanupSteps == OptimiserSettings::DefaultYulOptimiserCleanupSteps);
}

return settings;
Expand Down

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

34 changes: 0 additions & 34 deletions test/cmdlineTests/yul_optimizer_steps_with_cleanup_sequence/output

This file was deleted.

This file was deleted.

This file was deleted.

42 changes: 0 additions & 42 deletions test/cmdlineTests/yul_optimizer_steps_with_empty_sequences/output

This file was deleted.

Loading

0 comments on commit e37dc8e

Please sign in to comment.