mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #13376 from ethereum/make-hardcoded-parts-of-optimizer-sequence-configurable
This commit is contained in:
commit
ea78c8fd31
@ -4,6 +4,7 @@ Language Features:
|
|||||||
|
|
||||||
|
|
||||||
Compiler 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.
|
||||||
|
|
||||||
|
|
||||||
Bugfixes:
|
Bugfixes:
|
||||||
|
@ -281,60 +281,85 @@ The following transformation steps are the main components:
|
|||||||
- Redundant Assign Eliminator
|
- Redundant Assign Eliminator
|
||||||
- Full Inliner
|
- Full Inliner
|
||||||
|
|
||||||
|
.. _optimizer-steps:
|
||||||
|
|
||||||
Optimizer Steps
|
Optimizer Steps
|
||||||
---------------
|
---------------
|
||||||
|
|
||||||
This is a list of all steps the Yul-based optimizer sorted alphabetically. You can find more information
|
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.
|
on the individual steps and their sequence below.
|
||||||
|
|
||||||
- :ref:`block-flattener`.
|
============ ===============================
|
||||||
- :ref:`circular-reference-pruner`.
|
Abbreviation Full name
|
||||||
- :ref:`common-subexpression-eliminator`.
|
============ ===============================
|
||||||
- :ref:`conditional-simplifier`.
|
``f`` :ref:`block-flattener`
|
||||||
- :ref:`conditional-unsimplifier`.
|
``l`` :ref:`circular-reference-pruner`
|
||||||
- :ref:`control-flow-simplifier`.
|
``c`` :ref:`common-subexpression-eliminator`
|
||||||
- :ref:`dead-code-eliminator`.
|
``C`` :ref:`conditional-simplifier`
|
||||||
- :ref:`equal-store-eliminator`.
|
``U`` :ref:`conditional-unsimplifier`
|
||||||
- :ref:`equivalent-function-combiner`.
|
``n`` :ref:`control-flow-simplifier`
|
||||||
- :ref:`expression-joiner`.
|
``D`` :ref:`dead-code-eliminator`
|
||||||
- :ref:`expression-simplifier`.
|
``E`` :ref:`equal-store-eliminator`
|
||||||
- :ref:`expression-splitter`.
|
``v`` :ref:`equivalent-function-combiner`
|
||||||
- :ref:`for-loop-condition-into-body`.
|
``e`` :ref:`expression-inliner`
|
||||||
- :ref:`for-loop-condition-out-of-body`.
|
``j`` :ref:`expression-joiner`
|
||||||
- :ref:`for-loop-init-rewriter`.
|
``s`` :ref:`expression-simplifier`
|
||||||
- :ref:`expression-inliner`.
|
``x`` :ref:`expression-splitter`
|
||||||
- :ref:`full-inliner`.
|
``I`` :ref:`for-loop-condition-into-body`
|
||||||
- :ref:`function-grouper`.
|
``O`` :ref:`for-loop-condition-out-of-body`
|
||||||
- :ref:`function-hoister`.
|
``o`` :ref:`for-loop-init-rewriter`
|
||||||
- :ref:`function-specializer`.
|
``i`` :ref:`full-inliner`
|
||||||
- :ref:`literal-rematerialiser`.
|
``g`` :ref:`function-grouper`
|
||||||
- :ref:`load-resolver`.
|
``h`` :ref:`function-hoister`
|
||||||
- :ref:`loop-invariant-code-motion`.
|
``F`` :ref:`function-specializer`
|
||||||
- :ref:`redundant-assign-eliminator`.
|
``T`` :ref:`literal-rematerialiser`
|
||||||
- :ref:`reasoning-based-simplifier`.
|
``L`` :ref:`load-resolver`
|
||||||
- :ref:`rematerialiser`.
|
``M`` :ref:`loop-invariant-code-motion`
|
||||||
- :ref:`SSA-reverser`.
|
``r`` :ref:`redundant-assign-eliminator`
|
||||||
- :ref:`SSA-transform`.
|
``R`` :ref:`reasoning-based-simplifier` - highly experimental
|
||||||
- :ref:`structural-simplifier`.
|
``m`` :ref:`rematerialiser`
|
||||||
- :ref:`unused-function-parameter-pruner`.
|
``V`` :ref:`SSA-reverser`
|
||||||
- :ref:`unused-pruner`.
|
``a`` :ref:`SSA-transform`
|
||||||
- :ref:`var-decl-initializer`.
|
``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
|
Selecting Optimizations
|
||||||
-----------------------
|
-----------------------
|
||||||
|
|
||||||
By default the optimizer applies its predefined sequence of optimization steps to
|
By default the optimizer applies its predefined sequence of optimization steps to the generated assembly.
|
||||||
the generated assembly. You can override this sequence and supply your own using
|
You can override this sequence and supply your own using the ``--yul-optimizations`` option:
|
||||||
the ``--yul-optimizations`` option:
|
|
||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
|
||||||
solc --optimize --ir-optimized --yul-optimizations 'dhfoD[xarrscLMcCTU]uljmul'
|
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
|
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.
|
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.
|
||||||
|
|
||||||
Available abbreviations are listed in the :ref:`Yul optimizer docs <optimization-step-sequence>`.
|
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
|
Preprocessing
|
||||||
-------------
|
-------------
|
||||||
|
61
docs/yul.rst
61
docs/yul.rst
@ -1245,65 +1245,8 @@ In Solidity mode, the Yul optimizer is activated together with the regular optim
|
|||||||
Optimization Step Sequence
|
Optimization Step Sequence
|
||||||
--------------------------
|
--------------------------
|
||||||
|
|
||||||
By default the Yul optimizer applies its predefined sequence of optimization steps to the generated assembly.
|
Detailed information regrading the optimization sequence as well a list of abbreviations is
|
||||||
You can override this sequence and supply your own using the ``--yul-optimizations`` option:
|
available in the :ref:`optimizer docs <optimizer-steps>`.
|
||||||
|
|
||||||
.. code-block:: sh
|
|
||||||
|
|
||||||
solc --optimize --ir-optimized --yul-optimizations 'dhfoD[xarrscLMcCTU]uljmul'
|
|
||||||
|
|
||||||
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.
|
|
||||||
By enclosing part of the sequence in square brackets (``[]``) you tell the optimizer to repeatedly
|
|
||||||
apply that part until it no longer improves the size of the resulting assembly.
|
|
||||||
You can use brackets multiple times in a single sequence but they cannot be nested.
|
|
||||||
|
|
||||||
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!
|
|
||||||
|
|
||||||
.. _erc20yul:
|
.. _erc20yul:
|
||||||
|
|
||||||
|
@ -547,6 +547,7 @@ void CompilerContext::optimizeYul(yul::Object& _object, yul::EVMDialect const& _
|
|||||||
_object,
|
_object,
|
||||||
_optimiserSettings.optimizeStackAllocation,
|
_optimiserSettings.optimizeStackAllocation,
|
||||||
_optimiserSettings.yulOptimiserSteps,
|
_optimiserSettings.yulOptimiserSteps,
|
||||||
|
_optimiserSettings.yulOptimiserCleanupSteps,
|
||||||
isCreation? nullopt : make_optional(_optimiserSettings.expectedExecutionsPerDeployment),
|
isCreation? nullopt : make_optional(_optimiserSettings.expectedExecutionsPerDeployment),
|
||||||
_externalIdentifiers
|
_externalIdentifiers
|
||||||
);
|
);
|
||||||
|
@ -1539,7 +1539,7 @@ string CompilerStack::createMetadata(Contract const& _contract, bool _forIR) con
|
|||||||
{
|
{
|
||||||
details["yulDetails"] = Json::objectValue;
|
details["yulDetails"] = Json::objectValue;
|
||||||
details["yulDetails"]["stackAllocation"] = m_optimiserSettings.optimizeStackAllocation;
|
details["yulDetails"]["stackAllocation"] = m_optimiserSettings.optimizeStackAllocation;
|
||||||
details["yulDetails"]["optimizerSteps"] = m_optimiserSettings.yulOptimiserSteps;
|
details["yulDetails"]["optimizerSteps"] = m_optimiserSettings.yulOptimiserSteps + ":" + m_optimiserSettings.yulOptimiserCleanupSteps;
|
||||||
}
|
}
|
||||||
|
|
||||||
meta["settings"]["optimizer"]["details"] = std::move(details);
|
meta["settings"]["optimizer"]["details"] = std::move(details);
|
||||||
|
@ -59,6 +59,8 @@ struct OptimiserSettings
|
|||||||
"]"
|
"]"
|
||||||
"jmul[jul] VcTOcul jmul"; // Make source short and pretty
|
"jmul[jul] VcTOcul jmul"; // Make source short and pretty
|
||||||
|
|
||||||
|
static char constexpr DefaultYulOptimiserCleanupSteps[] = "fDnTOc";
|
||||||
|
|
||||||
/// No optimisations at all - not recommended.
|
/// No optimisations at all - not recommended.
|
||||||
static OptimiserSettings none()
|
static OptimiserSettings none()
|
||||||
{
|
{
|
||||||
@ -146,6 +148,10 @@ struct OptimiserSettings
|
|||||||
/// them just by setting this to an empty string. Set @a runYulOptimiser to false if you want
|
/// them just by setting this to an empty string. Set @a runYulOptimiser to false if you want
|
||||||
/// no optimisations.
|
/// no optimisations.
|
||||||
std::string yulOptimiserSteps = DefaultYulOptimiserSteps;
|
std::string yulOptimiserSteps = DefaultYulOptimiserSteps;
|
||||||
|
/// Sequence of clean-up optimisation steps after yulOptimiserSteps is run. Note that if the string
|
||||||
|
/// is left empty, there will still be hard-coded optimisation steps that will run regardless.
|
||||||
|
/// Set @a runYulOptimiser to false if you want no optimisations.
|
||||||
|
std::string yulOptimiserCleanupSteps = DefaultYulOptimiserCleanupSteps;
|
||||||
/// This specifies an estimate on how often each opcode in this assembly will be executed,
|
/// This specifies an estimate on how often each opcode in this assembly will be executed,
|
||||||
/// i.e. use a small value to optimise for size and a large value to optimise for runtime gas usage.
|
/// i.e. use a small value to optimise for size and a large value to optimise for runtime gas usage.
|
||||||
size_t expectedExecutionsPerDeployment = 200;
|
size_t expectedExecutionsPerDeployment = 200;
|
||||||
|
@ -472,7 +472,7 @@ std::optional<Json::Value> checkOptimizerDetail(Json::Value const& _details, std
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<Json::Value> checkOptimizerDetailSteps(Json::Value const& _details, std::string const& _name, string& _setting)
|
std::optional<Json::Value> checkOptimizerDetailSteps(Json::Value const& _details, std::string const& _name, string& _optimiserSetting, string& _cleanupSetting)
|
||||||
{
|
{
|
||||||
if (_details.isMember(_name))
|
if (_details.isMember(_name))
|
||||||
{
|
{
|
||||||
@ -490,7 +490,14 @@ std::optional<Json::Value> checkOptimizerDetailSteps(Json::Value const& _details
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
_setting = _details[_name].asString();
|
string const fullSequence = _details[_name].asString();
|
||||||
|
auto const delimiterPos = fullSequence.find(":");
|
||||||
|
_optimiserSetting = fullSequence.substr(0, delimiterPos);
|
||||||
|
|
||||||
|
if (delimiterPos != string::npos)
|
||||||
|
_cleanupSetting = fullSequence.substr(delimiterPos + 1);
|
||||||
|
else
|
||||||
|
solAssert(_cleanupSetting == OptimiserSettings::DefaultYulOptimiserCleanupSteps);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
return formatFatalError("JSONError", "\"settings.optimizer.details." + _name + "\" must be a string");
|
return formatFatalError("JSONError", "\"settings.optimizer.details." + _name + "\" must be a string");
|
||||||
@ -616,7 +623,7 @@ std::variant<OptimiserSettings, Json::Value> parseOptimizerSettings(Json::Value
|
|||||||
return *result;
|
return *result;
|
||||||
if (auto error = checkOptimizerDetail(details["yulDetails"], "stackAllocation", settings.optimizeStackAllocation))
|
if (auto error = checkOptimizerDetail(details["yulDetails"], "stackAllocation", settings.optimizeStackAllocation))
|
||||||
return *error;
|
return *error;
|
||||||
if (auto error = checkOptimizerDetailSteps(details["yulDetails"], "optimizerSteps", settings.yulOptimiserSteps))
|
if (auto error = checkOptimizerDetailSteps(details["yulDetails"], "optimizerSteps", settings.yulOptimiserSteps, settings.yulOptimiserCleanupSteps))
|
||||||
return *error;
|
return *error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -209,6 +209,7 @@ void YulStack::optimize(Object& _object, bool _isCreation)
|
|||||||
_object,
|
_object,
|
||||||
m_optimiserSettings.optimizeStackAllocation,
|
m_optimiserSettings.optimizeStackAllocation,
|
||||||
m_optimiserSettings.yulOptimiserSteps,
|
m_optimiserSettings.yulOptimiserSteps,
|
||||||
|
m_optimiserSettings.yulOptimiserCleanupSteps,
|
||||||
_isCreation ? nullopt : make_optional(m_optimiserSettings.expectedExecutionsPerDeployment),
|
_isCreation ? nullopt : make_optional(m_optimiserSettings.expectedExecutionsPerDeployment),
|
||||||
{}
|
{}
|
||||||
);
|
);
|
||||||
|
@ -93,6 +93,7 @@ void OptimiserSuite::run(
|
|||||||
Object& _object,
|
Object& _object,
|
||||||
bool _optimizeStackAllocation,
|
bool _optimizeStackAllocation,
|
||||||
string_view _optimisationSequence,
|
string_view _optimisationSequence,
|
||||||
|
string_view _optimisationCleanupSequence,
|
||||||
optional<size_t> _expectedExecutionsPerDeployment,
|
optional<size_t> _expectedExecutionsPerDeployment,
|
||||||
set<YulString> const& _externallyUsedIdentifiers
|
set<YulString> const& _externallyUsedIdentifiers
|
||||||
)
|
)
|
||||||
@ -139,7 +140,13 @@ void OptimiserSuite::run(
|
|||||||
_optimizeStackAllocation,
|
_optimizeStackAllocation,
|
||||||
stackCompressorMaxIterations
|
stackCompressorMaxIterations
|
||||||
);
|
);
|
||||||
suite.runSequence("fDnTOc g", ast);
|
|
||||||
|
// 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)
|
if (evmDialect)
|
||||||
{
|
{
|
||||||
@ -296,6 +303,7 @@ map<char, string> const& OptimiserSuite::stepAbbreviationToNameMap()
|
|||||||
void OptimiserSuite::validateSequence(string_view _stepAbbreviations)
|
void OptimiserSuite::validateSequence(string_view _stepAbbreviations)
|
||||||
{
|
{
|
||||||
int8_t nestingLevel = 0;
|
int8_t nestingLevel = 0;
|
||||||
|
int8_t colonDelimiters = 0;
|
||||||
for (char abbreviation: _stepAbbreviations)
|
for (char abbreviation: _stepAbbreviations)
|
||||||
switch (abbreviation)
|
switch (abbreviation)
|
||||||
{
|
{
|
||||||
@ -310,6 +318,11 @@ void OptimiserSuite::validateSequence(string_view _stepAbbreviations)
|
|||||||
nestingLevel--;
|
nestingLevel--;
|
||||||
assertThrow(nestingLevel >= 0, OptimizerException, "Unbalanced brackets");
|
assertThrow(nestingLevel >= 0, OptimizerException, "Unbalanced brackets");
|
||||||
break;
|
break;
|
||||||
|
case ':':
|
||||||
|
++colonDelimiters;
|
||||||
|
assertThrow(nestingLevel == 0, OptimizerException, "Cleanup sequence delimiter cannot be placed inside the brackets");
|
||||||
|
assertThrow(colonDelimiters <= 1, OptimizerException, "Too many cleanup sequence delimiters");
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
yulAssert(
|
yulAssert(
|
||||||
|
@ -51,7 +51,7 @@ public:
|
|||||||
|
|
||||||
/// Special characters that do not represent optimiser steps but are allowed in abbreviation sequences.
|
/// Special characters that do not represent optimiser steps but are allowed in abbreviation sequences.
|
||||||
/// Some of them (like whitespace) are ignored, others (like brackets) are a part of the syntax.
|
/// Some of them (like whitespace) are ignored, others (like brackets) are a part of the syntax.
|
||||||
static constexpr char NonStepAbbreviations[] = " \n[]";
|
static constexpr char NonStepAbbreviations[] = " \n[]:";
|
||||||
|
|
||||||
enum class Debug
|
enum class Debug
|
||||||
{
|
{
|
||||||
@ -68,6 +68,7 @@ public:
|
|||||||
Object& _object,
|
Object& _object,
|
||||||
bool _optimizeStackAllocation,
|
bool _optimizeStackAllocation,
|
||||||
std::string_view _optimisationSequence,
|
std::string_view _optimisationSequence,
|
||||||
|
std::string_view _optimisationCleanupSequence,
|
||||||
std::optional<size_t> _expectedExecutionsPerDeployment,
|
std::optional<size_t> _expectedExecutionsPerDeployment,
|
||||||
std::set<YulString> const& _externallyUsedIdentifiers = {}
|
std::set<YulString> const& _externallyUsedIdentifiers = {}
|
||||||
);
|
);
|
||||||
|
@ -266,7 +266,16 @@ OptimiserSettings CommandLineOptions::optimiserSettings() const
|
|||||||
settings.expectedExecutionsPerDeployment = optimizer.expectedExecutionsPerDeployment.value();
|
settings.expectedExecutionsPerDeployment = optimizer.expectedExecutionsPerDeployment.value();
|
||||||
|
|
||||||
if (optimizer.yulSteps.has_value())
|
if (optimizer.yulSteps.has_value())
|
||||||
settings.yulOptimiserSteps = optimizer.yulSteps.value();
|
{
|
||||||
|
string const fullSequence = optimizer.yulSteps.value();
|
||||||
|
auto const delimiterPos = fullSequence.find(":");
|
||||||
|
settings.yulOptimiserSteps = fullSequence.substr(0, delimiterPos);
|
||||||
|
|
||||||
|
if (delimiterPos != string::npos)
|
||||||
|
settings.yulOptimiserCleanupSteps = fullSequence.substr(delimiterPos + 1);
|
||||||
|
else
|
||||||
|
solAssert(settings.yulOptimiserCleanupSteps == OptimiserSettings::DefaultYulOptimiserCleanupSteps);
|
||||||
|
}
|
||||||
|
|
||||||
return settings;
|
return settings;
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1 @@
|
|||||||
|
--pretty-json --json-indent 4
|
@ -0,0 +1,6 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-3.0
|
||||||
|
pragma solidity >=0.0;
|
||||||
|
|
||||||
|
contract C {
|
||||||
|
function f() public pure {}
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"language": "Solidity",
|
||||||
|
"sources": {
|
||||||
|
"A": {"urls": ["standard_optimizer_yulDetails_optimiserSteps_invalid_nested_delimiter/in.sol"]}
|
||||||
|
},
|
||||||
|
"settings": {
|
||||||
|
"optimizer": {
|
||||||
|
"details": {
|
||||||
|
"yul": true,
|
||||||
|
"yulDetails": {
|
||||||
|
"optimizerSteps": "dhfoDgvulfnTUtnIf\n[ xar:rscLM\n]\njmuljuljul VcTOcul jmul"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"errors":
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"component": "general",
|
||||||
|
"formattedMessage": "Invalid optimizer step sequence in \"settings.optimizer.details.optimizerSteps\": Cleanup sequence delimiter cannot be placed inside the brackets",
|
||||||
|
"message": "Invalid optimizer step sequence in \"settings.optimizer.details.optimizerSteps\": Cleanup sequence delimiter cannot be placed inside the brackets",
|
||||||
|
"severity": "error",
|
||||||
|
"type": "JSONError"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -0,0 +1 @@
|
|||||||
|
--pretty-json --json-indent 4
|
@ -0,0 +1,6 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-3.0
|
||||||
|
pragma solidity >=0.0;
|
||||||
|
|
||||||
|
contract C {
|
||||||
|
function f() public pure {}
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"language": "Solidity",
|
||||||
|
"sources": {
|
||||||
|
"A": {"urls": ["standard_optimizer_yulDetails_optimiserSteps_mutliple_delimiters/in.sol"]}
|
||||||
|
},
|
||||||
|
"settings": {
|
||||||
|
"optimizer": {
|
||||||
|
"details": {
|
||||||
|
"yul": true,
|
||||||
|
"yulDetails": {
|
||||||
|
"optimizerSteps": "dhfoDgvu:lfnTUtnIf\n[ xarrscLM\n]\njmuljulj:ul VcTOcul jmul"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"errors":
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"component": "general",
|
||||||
|
"formattedMessage": "Invalid optimizer step sequence in \"settings.optimizer.details.optimizerSteps\": Too many cleanup sequence delimiters",
|
||||||
|
"message": "Invalid optimizer step sequence in \"settings.optimizer.details.optimizerSteps\": Too many cleanup sequence delimiters",
|
||||||
|
"severity": "error",
|
||||||
|
"type": "JSONError"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -0,0 +1 @@
|
|||||||
|
--pretty-json --json-indent 4
|
@ -0,0 +1,6 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-3.0
|
||||||
|
pragma solidity >=0.0;
|
||||||
|
|
||||||
|
contract C {
|
||||||
|
function f() public pure {}
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"language": "Solidity",
|
||||||
|
"sources": {
|
||||||
|
"A": {"urls": ["standard_optimizer_yulDetails_optimiserSteps_with_cleanup_sequence/in.sol"]}
|
||||||
|
},
|
||||||
|
"settings": {
|
||||||
|
"optimizer": {
|
||||||
|
"details": {
|
||||||
|
"yul": true,
|
||||||
|
"yulDetails": {
|
||||||
|
"optimizerSteps": "dhfoDgvulfnTUtnIf\n[ xarrscLM\n]\njmuljuljul VcTOcul jmul:fDnTOc"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"sources":
|
||||||
|
{
|
||||||
|
"A":
|
||||||
|
{
|
||||||
|
"id": 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1 @@
|
|||||||
|
--pretty-json --json-indent 4
|
@ -0,0 +1,6 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-3.0
|
||||||
|
pragma solidity >=0.0;
|
||||||
|
|
||||||
|
contract C {
|
||||||
|
function f() public pure {}
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"language": "Solidity",
|
||||||
|
"sources": {
|
||||||
|
"A": {"urls": ["standard_optimizer_yulDetails_optimiserSteps_with_cleanup_sequence/in.sol"]}
|
||||||
|
},
|
||||||
|
"settings": {
|
||||||
|
"optimizer": {
|
||||||
|
"details": {
|
||||||
|
"yul": true,
|
||||||
|
"yulDetails": {
|
||||||
|
"optimizerSteps": "dhfoDgvulfnTUtnIf\n[ xarrscLM\n]\njmuljuljul VcTOcul jmul:"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"sources":
|
||||||
|
{
|
||||||
|
"A":
|
||||||
|
{
|
||||||
|
"id": 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1 @@
|
|||||||
|
--pretty-json --json-indent 4
|
@ -0,0 +1,6 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-3.0
|
||||||
|
pragma solidity >=0.0;
|
||||||
|
|
||||||
|
contract C {
|
||||||
|
function f() public pure {}
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"language": "Solidity",
|
||||||
|
"sources": {
|
||||||
|
"A": {"urls": ["standard_optimizer_yulDetails_optimiserSteps_with_cleanup_sequence/in.sol"]}
|
||||||
|
},
|
||||||
|
"settings": {
|
||||||
|
"optimizer": {
|
||||||
|
"details": {
|
||||||
|
"yul": true,
|
||||||
|
"yulDetails": {
|
||||||
|
"optimizerSteps": ":dhfoDgvulfnTUtnIf\n[ xarrscLM\n]\njmuljuljul VcTOcul jmul"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"sources":
|
||||||
|
{
|
||||||
|
"A":
|
||||||
|
{
|
||||||
|
"id": 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1 @@
|
|||||||
|
--pretty-json --json-indent 4
|
@ -0,0 +1,6 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-3.0
|
||||||
|
pragma solidity >=0.0;
|
||||||
|
|
||||||
|
contract C {
|
||||||
|
function f() public pure {}
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"language": "Solidity",
|
||||||
|
"sources": {
|
||||||
|
"A": {"urls": ["standard_optimizer_yulDetails_optimiserSteps_with_cleanup_sequence/in.sol"]}
|
||||||
|
},
|
||||||
|
"settings": {
|
||||||
|
"optimizer": {
|
||||||
|
"details": {
|
||||||
|
"yul": true,
|
||||||
|
"yulDetails": {
|
||||||
|
"optimizerSteps": ":"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"sources":
|
||||||
|
{
|
||||||
|
"A":
|
||||||
|
{
|
||||||
|
"id": 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1 @@
|
|||||||
|
--ir-optimized --optimize --yul-optimizations iDu
|
@ -0,0 +1,12 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-3.0
|
||||||
|
pragma solidity >=0.0;
|
||||||
|
pragma abicoder v2;
|
||||||
|
|
||||||
|
contract C {
|
||||||
|
constructor() payable {
|
||||||
|
assembly ("memory-safe") {
|
||||||
|
let a := 0
|
||||||
|
revert(0, a)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
24
test/cmdlineTests/yul_optimizer_steps_short_sequence/output
Normal file
24
test/cmdlineTests/yul_optimizer_steps_short_sequence/output
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
Optimized IR:
|
||||||
|
/// @use-src 0:"yul_optimizer_steps_short_sequence/input.sol"
|
||||||
|
object "C_8" {
|
||||||
|
code {
|
||||||
|
{
|
||||||
|
/// @src 0:80:221 "contract C {..."
|
||||||
|
mstore(64, memoryguard(0x80))
|
||||||
|
/// @src 0:129:213 "assembly (\"memory-safe\") {..."
|
||||||
|
let usr$a := 0
|
||||||
|
revert(usr$a, usr$a)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// @use-src 0:"yul_optimizer_steps_short_sequence/input.sol"
|
||||||
|
object "C_8_deployed" {
|
||||||
|
code {
|
||||||
|
{
|
||||||
|
/// @src 0:80:221 "contract C {..."
|
||||||
|
mstore(64, memoryguard(0x80))
|
||||||
|
revert(0, 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
data ".metadata" hex"<BYTECODE REMOVED>"
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1 @@
|
|||||||
|
--ir-optimized --optimize --yul-optimizations iDu:
|
@ -0,0 +1,13 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-3.0
|
||||||
|
pragma solidity >=0.0;
|
||||||
|
pragma abicoder v2;
|
||||||
|
|
||||||
|
contract C {
|
||||||
|
constructor() payable {
|
||||||
|
assembly ("memory-safe") {
|
||||||
|
let a := 0
|
||||||
|
// Without the cleanup sequence this will not be simplified to ``revert(a, a)``.
|
||||||
|
revert(0, a)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,24 @@
|
|||||||
|
Optimized IR:
|
||||||
|
/// @use-src 0:"yul_optimizer_steps_with_empty_cleanup_sequence/input.sol"
|
||||||
|
object "C_8" {
|
||||||
|
code {
|
||||||
|
{
|
||||||
|
/// @src 0:80:314 "contract C {..."
|
||||||
|
mstore(64, memoryguard(0x80))
|
||||||
|
/// @src 0:129:306 "assembly (\"memory-safe\") {..."
|
||||||
|
let usr$a := 0
|
||||||
|
revert(0, usr$a)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// @use-src 0:"yul_optimizer_steps_with_empty_cleanup_sequence/input.sol"
|
||||||
|
object "C_8_deployed" {
|
||||||
|
code {
|
||||||
|
{
|
||||||
|
/// @src 0:80:314 "contract C {..."
|
||||||
|
mstore(64, memoryguard(0x80))
|
||||||
|
revert(0, 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
data ".metadata" hex"<BYTECODE REMOVED>"
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1 @@
|
|||||||
|
--ir-optimized --optimize --yul-optimizations :iDu
|
@ -0,0 +1,13 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-3.0
|
||||||
|
pragma solidity >=0.0;
|
||||||
|
pragma abicoder v2;
|
||||||
|
|
||||||
|
contract C {
|
||||||
|
constructor() payable {
|
||||||
|
assembly ("memory-safe") {
|
||||||
|
let a := 0
|
||||||
|
// Without the cleanup sequence this will not be simplified to ``revert(a, a)``.
|
||||||
|
revert(0, a)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,24 @@
|
|||||||
|
Optimized IR:
|
||||||
|
/// @use-src 0:"yul_optimizer_steps_with_empty_optimization_sequence/input.sol"
|
||||||
|
object "C_8" {
|
||||||
|
code {
|
||||||
|
{
|
||||||
|
/// @src 0:80:314 "contract C {..."
|
||||||
|
mstore(64, memoryguard(0x80))
|
||||||
|
/// @src 0:129:306 "assembly (\"memory-safe\") {..."
|
||||||
|
let usr$a := 0
|
||||||
|
revert(0, usr$a)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// @use-src 0:"yul_optimizer_steps_with_empty_optimization_sequence/input.sol"
|
||||||
|
object "C_8_deployed" {
|
||||||
|
code {
|
||||||
|
{
|
||||||
|
/// @src 0:80:314 "contract C {..."
|
||||||
|
mstore(64, memoryguard(0x80))
|
||||||
|
revert(0, 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
data ".metadata" hex"<BYTECODE REMOVED>"
|
||||||
|
}
|
||||||
|
}
|
@ -400,6 +400,53 @@ BOOST_AUTO_TEST_CASE(metadata_revert_strings)
|
|||||||
BOOST_CHECK_EQUAL(metadata["settings"]["debug"]["revertStrings"], "strip");
|
BOOST_CHECK_EQUAL(metadata["settings"]["debug"]["revertStrings"], "strip");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(metadata_optimiser_sequence)
|
||||||
|
{
|
||||||
|
char const* sourceCode = R"(
|
||||||
|
pragma solidity >=0.0;
|
||||||
|
contract C {
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
|
||||||
|
vector<tuple<string, string>> sequences =
|
||||||
|
{
|
||||||
|
// {"<optimizer sequence>", "<optimizer cleanup sequence>"}
|
||||||
|
{"", ""},
|
||||||
|
{"", "fDn"},
|
||||||
|
{"dhfoDgvulfnTUtnIf", "" },
|
||||||
|
{"dhfoDgvulfnTUtnIf", "fDn"}
|
||||||
|
};
|
||||||
|
|
||||||
|
auto check = [sourceCode](string const& _optimizerSequence, string const& _optimizerCleanupSequence)
|
||||||
|
{
|
||||||
|
OptimiserSettings optimizerSettings = OptimiserSettings::minimal();
|
||||||
|
optimizerSettings.runYulOptimiser = true;
|
||||||
|
optimizerSettings.yulOptimiserSteps = _optimizerSequence;
|
||||||
|
optimizerSettings.yulOptimiserCleanupSteps = _optimizerCleanupSequence;
|
||||||
|
CompilerStack compilerStack;
|
||||||
|
compilerStack.setSources({{"", std::string(sourceCode)}});
|
||||||
|
compilerStack.setEVMVersion(solidity::test::CommonOptions::get().evmVersion());
|
||||||
|
compilerStack.setOptimiserSettings(optimizerSettings);
|
||||||
|
|
||||||
|
BOOST_REQUIRE_MESSAGE(compilerStack.compile(), "Compiling contract failed");
|
||||||
|
|
||||||
|
std::string const& serialisedMetadata = compilerStack.metadata("C");
|
||||||
|
Json::Value metadata;
|
||||||
|
BOOST_REQUIRE(util::jsonParseStrict(serialisedMetadata, metadata));
|
||||||
|
BOOST_CHECK(solidity::test::isValidMetadata(metadata));
|
||||||
|
BOOST_CHECK(metadata["settings"]["optimizer"].isMember("details"));
|
||||||
|
BOOST_CHECK(metadata["settings"]["optimizer"]["details"].isMember("yulDetails"));
|
||||||
|
BOOST_CHECK(metadata["settings"]["optimizer"]["details"]["yulDetails"].isMember("optimizerSteps"));
|
||||||
|
|
||||||
|
string const metadataOptimizerSteps = metadata["settings"]["optimizer"]["details"]["yulDetails"]["optimizerSteps"].asString();
|
||||||
|
string const expectedMetadataOptimiserSteps = _optimizerSequence + ":" + _optimizerCleanupSequence;
|
||||||
|
BOOST_CHECK_EQUAL(metadataOptimizerSteps, expectedMetadataOptimiserSteps);
|
||||||
|
};
|
||||||
|
|
||||||
|
for (auto const& [sequence, cleanupSequence] : sequences)
|
||||||
|
check(sequence, cleanupSequence);
|
||||||
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(metadata_license_missing)
|
BOOST_AUTO_TEST_CASE(metadata_license_missing)
|
||||||
{
|
{
|
||||||
char const* sourceCode = R"(
|
char const* sourceCode = R"(
|
||||||
|
@ -1247,7 +1247,10 @@ BOOST_AUTO_TEST_CASE(optimizer_settings_details_different)
|
|||||||
(set<string>{"stackAllocation", "optimizerSteps"})
|
(set<string>{"stackAllocation", "optimizerSteps"})
|
||||||
);
|
);
|
||||||
BOOST_CHECK(optimizer["details"]["yulDetails"]["stackAllocation"].asBool() == true);
|
BOOST_CHECK(optimizer["details"]["yulDetails"]["stackAllocation"].asBool() == true);
|
||||||
BOOST_CHECK(optimizer["details"]["yulDetails"]["optimizerSteps"].asString() == OptimiserSettings::DefaultYulOptimiserSteps);
|
BOOST_CHECK(
|
||||||
|
optimizer["details"]["yulDetails"]["optimizerSteps"].asString() ==
|
||||||
|
OptimiserSettings::DefaultYulOptimiserSteps + ":"s + OptimiserSettings::DefaultYulOptimiserCleanupSteps
|
||||||
|
);
|
||||||
BOOST_CHECK_EQUAL(optimizer["details"].getMemberNames().size(), 9);
|
BOOST_CHECK_EQUAL(optimizer["details"].getMemberNames().size(), 9);
|
||||||
BOOST_CHECK(optimizer["runs"].asUInt() == 600);
|
BOOST_CHECK(optimizer["runs"].asUInt() == 600);
|
||||||
}
|
}
|
||||||
|
@ -339,6 +339,7 @@ YulOptimizerTestCommon::YulOptimizerTestCommon(
|
|||||||
*m_object,
|
*m_object,
|
||||||
true,
|
true,
|
||||||
frontend::OptimiserSettings::DefaultYulOptimiserSteps,
|
frontend::OptimiserSettings::DefaultYulOptimiserSteps,
|
||||||
|
frontend::OptimiserSettings::DefaultYulOptimiserCleanupSteps,
|
||||||
frontend::OptimiserSettings::standard().expectedExecutionsPerDeployment
|
frontend::OptimiserSettings::standard().expectedExecutionsPerDeployment
|
||||||
);
|
);
|
||||||
}},
|
}},
|
||||||
|
@ -426,6 +426,58 @@ BOOST_AUTO_TEST_CASE(invalid_options_input_modes_combinations)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(default_optimiser_sequence)
|
||||||
|
{
|
||||||
|
CommandLineOptions const& commandLineOptions = parseCommandLine({"solc", "contract.sol", "--optimize"});
|
||||||
|
BOOST_CHECK_EQUAL(commandLineOptions.optimiserSettings().yulOptimiserSteps, OptimiserSettings::DefaultYulOptimiserSteps);
|
||||||
|
BOOST_CHECK_EQUAL(commandLineOptions.optimiserSettings().yulOptimiserCleanupSteps, OptimiserSettings::DefaultYulOptimiserCleanupSteps);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(valid_optimiser_sequences)
|
||||||
|
{
|
||||||
|
vector<string> validSequenceInputs {
|
||||||
|
":", // Empty optimization sequence and empty cleanup sequence
|
||||||
|
":fDn", // Empty optimization sequence and specified cleanup sequence
|
||||||
|
"dhfoDgvulfnTUtnIf:", // Specified optimization sequence and empty cleanup sequence
|
||||||
|
"dhfoDgvulfnTUtnIf:fDn", // Specified optimization sequence and cleanup sequence
|
||||||
|
"dhfo[Dgvulfn]TUtnIf:f[D]n" // Specified and nested optimization and cleanup sequence
|
||||||
|
};
|
||||||
|
|
||||||
|
vector<tuple<string, string>> expectedParsedSequences {
|
||||||
|
{"", ""},
|
||||||
|
{"", "fDn"},
|
||||||
|
{"dhfoDgvulfnTUtnIf", ""},
|
||||||
|
{"dhfoDgvulfnTUtnIf", "fDn"},
|
||||||
|
{"dhfo[Dgvulfn]TUtnIf", "f[D]n"}
|
||||||
|
};
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL(validSequenceInputs.size(), expectedParsedSequences.size());
|
||||||
|
|
||||||
|
for (size_t i = 0; i < validSequenceInputs.size(); ++i)
|
||||||
|
{
|
||||||
|
CommandLineOptions const& commandLineOptions = parseCommandLine({"solc", "contract.sol", "--optimize", "--yul-optimizations=" + validSequenceInputs[i]});
|
||||||
|
auto const& [expectedYulOptimiserSteps, expectedYulCleanupSteps] = expectedParsedSequences[i];
|
||||||
|
BOOST_CHECK_EQUAL(commandLineOptions.optimiserSettings().yulOptimiserSteps, expectedYulOptimiserSteps);
|
||||||
|
BOOST_CHECK_EQUAL(commandLineOptions.optimiserSettings().yulOptimiserCleanupSteps, expectedYulCleanupSteps);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(invalid_nested_cleanup_sequence_delimiter)
|
||||||
|
{
|
||||||
|
vector<string> commandLine {"solc", "contract.sol", "--optimize", "--yul-optimizations=dhfoDgvulfnTUt[nIf:fd]N"};
|
||||||
|
string expectedMessage = "Invalid optimizer step sequence in --yul-optimizations: Cleanup sequence delimiter cannot be placed inside the brackets";
|
||||||
|
auto hasCorrectMessage = [&](CommandLineValidationError const& _exception) { return _exception.what() == expectedMessage; };
|
||||||
|
BOOST_CHECK_EXCEPTION(parseCommandLine(commandLine), CommandLineValidationError, hasCorrectMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(too_many_cleanup_sequence_delimiters)
|
||||||
|
{
|
||||||
|
vector<string> commandLine {"solc", "contract.sol", "--optimize", "--yul-optimizations=dhfoDgvulfnTU:tnIf:fdN"};
|
||||||
|
string expectedMessage = "Invalid optimizer step sequence in --yul-optimizations: Too many cleanup sequence delimiters";
|
||||||
|
auto hasCorrectMessage = [&](CommandLineValidationError const& _exception) { return _exception.what() == expectedMessage; };
|
||||||
|
BOOST_CHECK_EXCEPTION(parseCommandLine(commandLine), CommandLineValidationError, hasCorrectMessage);
|
||||||
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_SUITE_END()
|
BOOST_AUTO_TEST_SUITE_END()
|
||||||
|
|
||||||
} // namespace solidity::frontend::test
|
} // namespace solidity::frontend::test
|
||||||
|
Loading…
Reference in New Issue
Block a user