mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Command line tests and minor touch ups
This commit is contained in:
parent
ddf0d784ac
commit
314a1cc92f
@ -323,22 +323,8 @@ on the individual steps and their sequence below.
|
||||
Selecting Optimizations
|
||||
-----------------------
|
||||
|
||||
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.
|
||||
|
||||
The colon delimiter ``:`` is used to supply a custom clean up sequence in order to replace the
|
||||
default (``fDnTOc``) one, which is run after the stack compressor when using the legacy EVM
|
||||
code transform.
|
||||
|
||||
Available abbreviations are listed in the :ref:`Yul optimizer docs <optimization-step-sequence>`.
|
||||
Detailed information regrading the optimization sequence as well a list of abbreviations is
|
||||
available in the :ref:`Yul optimizer docs <optimization-step-sequence>`.
|
||||
|
||||
Preprocessing
|
||||
-------------
|
||||
|
27
docs/yul.rst
27
docs/yul.rst
@ -1245,24 +1245,25 @@ In Solidity mode, the Yul optimizer is activated together with the regular optim
|
||||
Optimization Step Sequence
|
||||
--------------------------
|
||||
|
||||
By default the Yul 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:
|
||||
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:: sh
|
||||
.. 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.
|
||||
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 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.
|
||||
|
||||
The colon delimiter (``:``) in the example is used to specify a custom cleanup sequence, which is run after
|
||||
the main part of the sequence before the delimiter (and, when using the legacy EVM code transform,
|
||||
only *after* the stack compressor). If no such delimiter is present, the default cleanup sequence (``fDnTOc``)
|
||||
is run after the supplied sequence.
|
||||
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:
|
||||
|
@ -1540,6 +1540,7 @@ string CompilerStack::createMetadata(Contract const& _contract, bool _forIR) con
|
||||
details["yulDetails"] = Json::objectValue;
|
||||
details["yulDetails"]["stackAllocation"] = m_optimiserSettings.optimizeStackAllocation;
|
||||
details["yulDetails"]["optimizerSteps"] = m_optimiserSettings.yulOptimiserSteps;
|
||||
details["yulDetails"]["optimizerCleanupSteps"] = m_optimiserSettings.yulOptimiserCleanupSteps;
|
||||
}
|
||||
|
||||
meta["settings"]["optimizer"]["details"] = std::move(details);
|
||||
|
@ -148,10 +148,9 @@ struct OptimiserSettings
|
||||
/// them just by setting this to an empty string. Set @a runYulOptimiser to false if you want
|
||||
/// no optimisations.
|
||||
std::string yulOptimiserSteps = DefaultYulOptimiserSteps;
|
||||
/// Sequence of clean up optimisation steps after the above (default or user supplied) set of
|
||||
/// optimisation steps is completed. 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.
|
||||
/// 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,
|
||||
/// i.e. use a small value to optimise for size and a large value to optimise for runtime gas usage.
|
||||
|
@ -490,7 +490,7 @@ std::optional<Json::Value> checkOptimizerDetailSteps(Json::Value const& _details
|
||||
);
|
||||
}
|
||||
|
||||
std::string const fullSequence = _details[_name].asString();
|
||||
string const fullSequence = _details[_name].asString();
|
||||
auto const delimiterPos = fullSequence.find(":");
|
||||
_optimiserSetting = fullSequence.substr(0, delimiterPos);
|
||||
|
||||
|
@ -141,7 +141,7 @@ void OptimiserSuite::run(
|
||||
stackCompressorMaxIterations
|
||||
);
|
||||
|
||||
// Run the user supplied (otherwise default) clean up sequence
|
||||
// Run the user-supplied clean up sequence
|
||||
suite.runSequence(_optimisationCleanupSequence, ast);
|
||||
suite.runSequence("g", ast);
|
||||
|
||||
@ -316,8 +316,9 @@ void OptimiserSuite::validateSequence(string_view _stepAbbreviations)
|
||||
assertThrow(nestingLevel >= 0, OptimizerException, "Unbalanced brackets");
|
||||
break;
|
||||
case ':':
|
||||
assertThrow(nestingLevel == 0, OptimizerException, "Cleanup delimiter may only be placed at nesting level zero");
|
||||
assertThrow(++colonDelimiters <=1, OptimizerException, "Too many colon delimiters");
|
||||
++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:
|
||||
{
|
||||
|
@ -267,7 +267,7 @@ OptimiserSettings CommandLineOptions::optimiserSettings() const
|
||||
|
||||
if (optimizer.yulSteps.has_value())
|
||||
{
|
||||
std::string const fullSequence = optimizer.yulSteps.value();
|
||||
string const fullSequence = optimizer.yulSteps.value();
|
||||
auto const delimiterPos = fullSequence.find(":");
|
||||
settings.yulOptimiserSteps = fullSequence.substr(0, delimiterPos);
|
||||
|
||||
|
@ -3,8 +3,8 @@
|
||||
[
|
||||
{
|
||||
"component": "general",
|
||||
"formattedMessage": "Invalid optimizer step sequence in \"settings.optimizer.details.optimizerSteps\": Cleanup delimiter may only be placed at nesting level zero",
|
||||
"message": "Invalid optimizer step sequence in \"settings.optimizer.details.optimizerSteps\": Cleanup delimiter may only be placed at nesting level zero",
|
||||
"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"
|
||||
}
|
||||
|
@ -3,8 +3,8 @@
|
||||
[
|
||||
{
|
||||
"component": "general",
|
||||
"formattedMessage": "Invalid optimizer step sequence in \"settings.optimizer.details.optimizerSteps\": Too many colon delimiters",
|
||||
"message": "Invalid optimizer step sequence in \"settings.optimizer.details.optimizerSteps\": Too many colon delimiters",
|
||||
"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"
|
||||
}
|
||||
|
@ -1 +1 @@
|
||||
Invalid optimizer step sequence in --yul-optimizations: Cleanup delimiter may only be placed at nesting level zero
|
||||
Invalid optimizer step sequence in --yul-optimizations: Cleanup sequence delimiter cannot be placed inside the brackets
|
||||
|
@ -1 +1 @@
|
||||
Invalid optimizer step sequence in --yul-optimizations: Too many colon delimiters
|
||||
Invalid optimizer step sequence in --yul-optimizations: Too many cleanup sequence delimiters
|
||||
|
@ -6,8 +6,8 @@ contract C {
|
||||
constructor() payable {
|
||||
assembly ("memory-safe") {
|
||||
let a := 0
|
||||
revert(0, a)
|
||||
// Without the cleanup sequence this will not be simplified to ``revert(a, a)``.
|
||||
revert(0, a)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,8 +6,8 @@ contract C {
|
||||
constructor() payable {
|
||||
assembly ("memory-safe") {
|
||||
let a := 0
|
||||
revert(0, a)
|
||||
// Without the cleanup sequence this will not be simplified to ``revert(a, a)``.
|
||||
revert(0, a)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1244,10 +1244,11 @@ BOOST_AUTO_TEST_CASE(optimizer_settings_details_different)
|
||||
BOOST_CHECK(optimizer["details"]["yulDetails"].isObject());
|
||||
BOOST_CHECK(
|
||||
util::convertContainer<set<string>>(optimizer["details"]["yulDetails"].getMemberNames()) ==
|
||||
(set<string>{"stackAllocation", "optimizerSteps"})
|
||||
(set<string>{"stackAllocation", "optimizerSteps", "optimizerCleanupSteps"})
|
||||
);
|
||||
BOOST_CHECK(optimizer["details"]["yulDetails"]["stackAllocation"].asBool() == true);
|
||||
BOOST_CHECK(optimizer["details"]["yulDetails"]["optimizerSteps"].asString() == OptimiserSettings::DefaultYulOptimiserSteps);
|
||||
BOOST_CHECK(optimizer["details"]["yulDetails"]["optimizerCleanupSteps"].asString() == OptimiserSettings::DefaultYulOptimiserCleanupSteps);
|
||||
BOOST_CHECK_EQUAL(optimizer["details"].getMemberNames().size(), 9);
|
||||
BOOST_CHECK(optimizer["runs"].asUInt() == 600);
|
||||
}
|
||||
|
@ -426,6 +426,58 @@ BOOST_AUTO_TEST_CASE(invalid_options_input_modes_combinations)
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(default_optimiser_sequence)
|
||||
{
|
||||
auto 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 optimizaiton sequence and empty cleanup sequence
|
||||
":fDn", // Empty optimization sequence and specified cleanup sequence
|
||||
"dhfoDgvulfnTUtnIf:", // Specified optimizaiton 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)
|
||||
{
|
||||
auto 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()
|
||||
|
||||
} // namespace solidity::frontend::test
|
||||
|
Loading…
Reference in New Issue
Block a user