From f6f0d6a3602ba2c83ecfd7608fb9a27c20835eb2 Mon Sep 17 00:00:00 2001 From: Nikola Matic Date: Wed, 10 Aug 2022 15:57:01 +0200 Subject: [PATCH 1/5] Make hardcoded parts of the optimizer sequence configurable --- libsolidity/codegen/CompilerContext.cpp | 1 + libsolidity/interface/OptimiserSettings.h | 7 ++++ libsolidity/interface/StandardCompiler.cpp | 11 +++-- libyul/YulStack.cpp | 1 + libyul/optimiser/Suite.cpp | 11 ++++- libyul/optimiser/Suite.h | 3 +- solc/CommandLineParser.cpp | 9 +++- .../args | 1 + .../in.sol | 6 +++ .../input.json | 16 +++++++ .../output.json | 12 ++++++ .../args | 1 + .../in.sol | 6 +++ .../input.json | 16 +++++++ .../output.json | 12 ++++++ .../args | 1 + .../in.sol | 6 +++ .../input.json | 16 +++++++ .../output.json | 9 ++++ .../args | 1 + .../in.sol | 6 +++ .../input.json | 16 +++++++ .../output.json | 9 ++++ .../args | 1 + .../in.sol | 6 +++ .../input.json | 16 +++++++ .../output.json | 9 ++++ .../args | 1 + .../in.sol | 6 +++ .../input.json | 16 +++++++ .../output.json | 9 ++++ .../args | 1 + .../err | 1 + .../exit | 1 + .../input.sol | 7 ++++ .../args | 1 + .../err | 1 + .../exit | 1 + .../input.sol | 7 ++++ .../yul_optimizer_steps_short_sequence/args | 1 + .../input.sol | 12 ++++++ .../yul_optimizer_steps_short_sequence/output | 24 +++++++++++ .../args | 1 + .../input.sol | 8 ++++ .../output | 34 +++++++++++++++ .../args | 1 + .../input.sol | 12 ++++++ .../output | 24 +++++++++++ .../args | 1 + .../input.sol | 12 ++++++ .../output | 24 +++++++++++ .../args | 1 + .../input.sol | 8 ++++ .../output | 42 +++++++++++++++++++ test/libyul/YulOptimizerTestCommon.cpp | 1 + 55 files changed, 461 insertions(+), 6 deletions(-) create mode 100644 test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_invalid_nested_delimiter/args create mode 100644 test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_invalid_nested_delimiter/in.sol create mode 100644 test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_invalid_nested_delimiter/input.json create mode 100644 test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_invalid_nested_delimiter/output.json create mode 100644 test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_mutliple_delimiters/args create mode 100644 test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_mutliple_delimiters/in.sol create mode 100644 test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_mutliple_delimiters/input.json create mode 100644 test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_mutliple_delimiters/output.json create mode 100644 test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_with_cleanup_sequence/args create mode 100644 test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_with_cleanup_sequence/in.sol create mode 100644 test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_with_cleanup_sequence/input.json create mode 100644 test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_with_cleanup_sequence/output.json create mode 100644 test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_with_empty_cleanup_sequence/args create mode 100644 test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_with_empty_cleanup_sequence/in.sol create mode 100644 test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_with_empty_cleanup_sequence/input.json create mode 100644 test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_with_empty_cleanup_sequence/output.json create mode 100644 test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_with_empty_optimisation_sequence/args create mode 100644 test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_with_empty_optimisation_sequence/in.sol create mode 100644 test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_with_empty_optimisation_sequence/input.json create mode 100644 test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_with_empty_optimisation_sequence/output.json create mode 100644 test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_with_empty_sequence/args create mode 100644 test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_with_empty_sequence/in.sol create mode 100644 test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_with_empty_sequence/input.json create mode 100644 test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_with_empty_sequence/output.json create mode 100644 test/cmdlineTests/yul_optimizer_steps_invalid_nested_delimiter/args create mode 100644 test/cmdlineTests/yul_optimizer_steps_invalid_nested_delimiter/err create mode 100644 test/cmdlineTests/yul_optimizer_steps_invalid_nested_delimiter/exit create mode 100644 test/cmdlineTests/yul_optimizer_steps_invalid_nested_delimiter/input.sol create mode 100644 test/cmdlineTests/yul_optimizer_steps_multiple_delimiters/args create mode 100644 test/cmdlineTests/yul_optimizer_steps_multiple_delimiters/err create mode 100644 test/cmdlineTests/yul_optimizer_steps_multiple_delimiters/exit create mode 100644 test/cmdlineTests/yul_optimizer_steps_multiple_delimiters/input.sol create mode 100644 test/cmdlineTests/yul_optimizer_steps_short_sequence/args create mode 100644 test/cmdlineTests/yul_optimizer_steps_short_sequence/input.sol create mode 100644 test/cmdlineTests/yul_optimizer_steps_short_sequence/output create mode 100644 test/cmdlineTests/yul_optimizer_steps_with_cleanup_sequence/args create mode 100644 test/cmdlineTests/yul_optimizer_steps_with_cleanup_sequence/input.sol create mode 100644 test/cmdlineTests/yul_optimizer_steps_with_cleanup_sequence/output create mode 100644 test/cmdlineTests/yul_optimizer_steps_with_empty_cleanup_sequence/args create mode 100644 test/cmdlineTests/yul_optimizer_steps_with_empty_cleanup_sequence/input.sol create mode 100644 test/cmdlineTests/yul_optimizer_steps_with_empty_cleanup_sequence/output create mode 100644 test/cmdlineTests/yul_optimizer_steps_with_empty_optimization_sequence/args create mode 100644 test/cmdlineTests/yul_optimizer_steps_with_empty_optimization_sequence/input.sol create mode 100644 test/cmdlineTests/yul_optimizer_steps_with_empty_optimization_sequence/output create mode 100644 test/cmdlineTests/yul_optimizer_steps_with_empty_sequences/args create mode 100644 test/cmdlineTests/yul_optimizer_steps_with_empty_sequences/input.sol create mode 100644 test/cmdlineTests/yul_optimizer_steps_with_empty_sequences/output diff --git a/libsolidity/codegen/CompilerContext.cpp b/libsolidity/codegen/CompilerContext.cpp index f1cc5b6dd..948502e69 100644 --- a/libsolidity/codegen/CompilerContext.cpp +++ b/libsolidity/codegen/CompilerContext.cpp @@ -547,6 +547,7 @@ void CompilerContext::optimizeYul(yul::Object& _object, yul::EVMDialect const& _ _object, _optimiserSettings.optimizeStackAllocation, _optimiserSettings.yulOptimiserSteps, + _optimiserSettings.yulOptimiserCleanupSteps, isCreation? nullopt : make_optional(_optimiserSettings.expectedExecutionsPerDeployment), _externalIdentifiers ); diff --git a/libsolidity/interface/OptimiserSettings.h b/libsolidity/interface/OptimiserSettings.h index e233048c1..82324d3f7 100644 --- a/libsolidity/interface/OptimiserSettings.h +++ b/libsolidity/interface/OptimiserSettings.h @@ -59,6 +59,8 @@ struct OptimiserSettings "]" "jmul[jul] VcTOcul jmul"; // Make source short and pretty + static char constexpr DefaultYulOptimiserCleanupSteps[] = "fDnTOc"; + /// No optimisations at all - not recommended. static OptimiserSettings none() { @@ -146,6 +148,11 @@ 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. + 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. size_t expectedExecutionsPerDeployment = 200; diff --git a/libsolidity/interface/StandardCompiler.cpp b/libsolidity/interface/StandardCompiler.cpp index c6cd741c1..7ccb71d78 100644 --- a/libsolidity/interface/StandardCompiler.cpp +++ b/libsolidity/interface/StandardCompiler.cpp @@ -472,7 +472,7 @@ std::optional checkOptimizerDetail(Json::Value const& _details, std return {}; } -std::optional checkOptimizerDetailSteps(Json::Value const& _details, std::string const& _name, string& _setting) +std::optional checkOptimizerDetailSteps(Json::Value const& _details, std::string const& _name, string& _optimiserSetting, string& _cleanupSetting) { if (_details.isMember(_name)) { @@ -490,7 +490,12 @@ std::optional checkOptimizerDetailSteps(Json::Value const& _details ); } - _setting = _details[_name].asString(); + std::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 return formatFatalError("JSONError", "\"settings.optimizer.details." + _name + "\" must be a string"); @@ -616,7 +621,7 @@ std::variant parseOptimizerSettings(Json::Value return *result; if (auto error = checkOptimizerDetail(details["yulDetails"], "stackAllocation", settings.optimizeStackAllocation)) return *error; - if (auto error = checkOptimizerDetailSteps(details["yulDetails"], "optimizerSteps", settings.yulOptimiserSteps)) + if (auto error = checkOptimizerDetailSteps(details["yulDetails"], "optimizerSteps", settings.yulOptimiserSteps, settings.yulOptimiserCleanupSteps)) return *error; } } diff --git a/libyul/YulStack.cpp b/libyul/YulStack.cpp index 3bca7288c..7553ee469 100644 --- a/libyul/YulStack.cpp +++ b/libyul/YulStack.cpp @@ -209,6 +209,7 @@ void YulStack::optimize(Object& _object, bool _isCreation) _object, m_optimiserSettings.optimizeStackAllocation, m_optimiserSettings.yulOptimiserSteps, + m_optimiserSettings.yulOptimiserCleanupSteps, _isCreation ? nullopt : make_optional(m_optimiserSettings.expectedExecutionsPerDeployment), {} ); diff --git a/libyul/optimiser/Suite.cpp b/libyul/optimiser/Suite.cpp index 181c9bdcb..ae32b25c3 100644 --- a/libyul/optimiser/Suite.cpp +++ b/libyul/optimiser/Suite.cpp @@ -93,6 +93,7 @@ void OptimiserSuite::run( Object& _object, bool _optimizeStackAllocation, string_view _optimisationSequence, + string_view _optimisationCleanupSequence, optional _expectedExecutionsPerDeployment, set const& _externallyUsedIdentifiers ) @@ -139,7 +140,10 @@ void OptimiserSuite::run( _optimizeStackAllocation, stackCompressorMaxIterations ); - suite.runSequence("fDnTOc g", ast); + + // Run the user supplied (otherwise default) clean up sequence + suite.runSequence(_optimisationCleanupSequence, ast); + suite.runSequence("g", ast); if (evmDialect) { @@ -296,6 +300,7 @@ map const& OptimiserSuite::stepAbbreviationToNameMap() void OptimiserSuite::validateSequence(string_view _stepAbbreviations) { int8_t nestingLevel = 0; + int8_t colonDelimiters = 0; for (char abbreviation: _stepAbbreviations) switch (abbreviation) { @@ -310,6 +315,10 @@ void OptimiserSuite::validateSequence(string_view _stepAbbreviations) nestingLevel--; 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"); + break; default: { yulAssert( diff --git a/libyul/optimiser/Suite.h b/libyul/optimiser/Suite.h index 3c85fc559..2db6288c0 100644 --- a/libyul/optimiser/Suite.h +++ b/libyul/optimiser/Suite.h @@ -51,7 +51,7 @@ public: /// 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. - static constexpr char NonStepAbbreviations[] = " \n[]"; + static constexpr char NonStepAbbreviations[] = " \n[]:"; enum class Debug { @@ -68,6 +68,7 @@ public: Object& _object, bool _optimizeStackAllocation, std::string_view _optimisationSequence, + std::string_view _optimisationCleanupSequence, std::optional _expectedExecutionsPerDeployment, std::set const& _externallyUsedIdentifiers = {} ); diff --git a/solc/CommandLineParser.cpp b/solc/CommandLineParser.cpp index 2c765d0e3..ce2d4d044 100644 --- a/solc/CommandLineParser.cpp +++ b/solc/CommandLineParser.cpp @@ -266,7 +266,14 @@ OptimiserSettings CommandLineOptions::optimiserSettings() const settings.expectedExecutionsPerDeployment = optimizer.expectedExecutionsPerDeployment.value(); if (optimizer.yulSteps.has_value()) - settings.yulOptimiserSteps = optimizer.yulSteps.value(); + { + std::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); + } return settings; } diff --git a/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_invalid_nested_delimiter/args b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_invalid_nested_delimiter/args new file mode 100644 index 000000000..a905f1fe6 --- /dev/null +++ b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_invalid_nested_delimiter/args @@ -0,0 +1 @@ +--pretty-json --json-indent 4 diff --git a/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_invalid_nested_delimiter/in.sol b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_invalid_nested_delimiter/in.sol new file mode 100644 index 000000000..9e5350072 --- /dev/null +++ b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_invalid_nested_delimiter/in.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity >=0.0; + +contract C { + function f() public pure {} +} diff --git a/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_invalid_nested_delimiter/input.json b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_invalid_nested_delimiter/input.json new file mode 100644 index 000000000..5be769f76 --- /dev/null +++ b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_invalid_nested_delimiter/input.json @@ -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" + } + } + } + } +} diff --git a/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_invalid_nested_delimiter/output.json b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_invalid_nested_delimiter/output.json new file mode 100644 index 000000000..41c8a307f --- /dev/null +++ b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_invalid_nested_delimiter/output.json @@ -0,0 +1,12 @@ +{ + "errors": + [ + { + "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", + "severity": "error", + "type": "JSONError" + } + ] +} diff --git a/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_mutliple_delimiters/args b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_mutliple_delimiters/args new file mode 100644 index 000000000..a905f1fe6 --- /dev/null +++ b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_mutliple_delimiters/args @@ -0,0 +1 @@ +--pretty-json --json-indent 4 diff --git a/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_mutliple_delimiters/in.sol b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_mutliple_delimiters/in.sol new file mode 100644 index 000000000..9e5350072 --- /dev/null +++ b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_mutliple_delimiters/in.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity >=0.0; + +contract C { + function f() public pure {} +} diff --git a/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_mutliple_delimiters/input.json b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_mutliple_delimiters/input.json new file mode 100644 index 000000000..0bddd9d9d --- /dev/null +++ b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_mutliple_delimiters/input.json @@ -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" + } + } + } + } +} diff --git a/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_mutliple_delimiters/output.json b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_mutliple_delimiters/output.json new file mode 100644 index 000000000..b6778a492 --- /dev/null +++ b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_mutliple_delimiters/output.json @@ -0,0 +1,12 @@ +{ + "errors": + [ + { + "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", + "severity": "error", + "type": "JSONError" + } + ] +} diff --git a/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_with_cleanup_sequence/args b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_with_cleanup_sequence/args new file mode 100644 index 000000000..a905f1fe6 --- /dev/null +++ b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_with_cleanup_sequence/args @@ -0,0 +1 @@ +--pretty-json --json-indent 4 diff --git a/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_with_cleanup_sequence/in.sol b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_with_cleanup_sequence/in.sol new file mode 100644 index 000000000..9e5350072 --- /dev/null +++ b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_with_cleanup_sequence/in.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity >=0.0; + +contract C { + function f() public pure {} +} diff --git a/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_with_cleanup_sequence/input.json b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_with_cleanup_sequence/input.json new file mode 100644 index 000000000..b557a9662 --- /dev/null +++ b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_with_cleanup_sequence/input.json @@ -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" + } + } + } + } +} diff --git a/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_with_cleanup_sequence/output.json b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_with_cleanup_sequence/output.json new file mode 100644 index 000000000..acf3b74ef --- /dev/null +++ b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_with_cleanup_sequence/output.json @@ -0,0 +1,9 @@ +{ + "sources": + { + "A": + { + "id": 0 + } + } +} diff --git a/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_with_empty_cleanup_sequence/args b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_with_empty_cleanup_sequence/args new file mode 100644 index 000000000..a905f1fe6 --- /dev/null +++ b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_with_empty_cleanup_sequence/args @@ -0,0 +1 @@ +--pretty-json --json-indent 4 diff --git a/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_with_empty_cleanup_sequence/in.sol b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_with_empty_cleanup_sequence/in.sol new file mode 100644 index 000000000..9e5350072 --- /dev/null +++ b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_with_empty_cleanup_sequence/in.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity >=0.0; + +contract C { + function f() public pure {} +} diff --git a/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_with_empty_cleanup_sequence/input.json b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_with_empty_cleanup_sequence/input.json new file mode 100644 index 000000000..0903ccfeb --- /dev/null +++ b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_with_empty_cleanup_sequence/input.json @@ -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:" + } + } + } + } +} diff --git a/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_with_empty_cleanup_sequence/output.json b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_with_empty_cleanup_sequence/output.json new file mode 100644 index 000000000..acf3b74ef --- /dev/null +++ b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_with_empty_cleanup_sequence/output.json @@ -0,0 +1,9 @@ +{ + "sources": + { + "A": + { + "id": 0 + } + } +} diff --git a/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_with_empty_optimisation_sequence/args b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_with_empty_optimisation_sequence/args new file mode 100644 index 000000000..a905f1fe6 --- /dev/null +++ b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_with_empty_optimisation_sequence/args @@ -0,0 +1 @@ +--pretty-json --json-indent 4 diff --git a/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_with_empty_optimisation_sequence/in.sol b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_with_empty_optimisation_sequence/in.sol new file mode 100644 index 000000000..9e5350072 --- /dev/null +++ b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_with_empty_optimisation_sequence/in.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity >=0.0; + +contract C { + function f() public pure {} +} diff --git a/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_with_empty_optimisation_sequence/input.json b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_with_empty_optimisation_sequence/input.json new file mode 100644 index 000000000..4086aff9f --- /dev/null +++ b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_with_empty_optimisation_sequence/input.json @@ -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" + } + } + } + } +} diff --git a/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_with_empty_optimisation_sequence/output.json b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_with_empty_optimisation_sequence/output.json new file mode 100644 index 000000000..acf3b74ef --- /dev/null +++ b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_with_empty_optimisation_sequence/output.json @@ -0,0 +1,9 @@ +{ + "sources": + { + "A": + { + "id": 0 + } + } +} diff --git a/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_with_empty_sequence/args b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_with_empty_sequence/args new file mode 100644 index 000000000..a905f1fe6 --- /dev/null +++ b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_with_empty_sequence/args @@ -0,0 +1 @@ +--pretty-json --json-indent 4 diff --git a/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_with_empty_sequence/in.sol b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_with_empty_sequence/in.sol new file mode 100644 index 000000000..9e5350072 --- /dev/null +++ b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_with_empty_sequence/in.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity >=0.0; + +contract C { + function f() public pure {} +} diff --git a/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_with_empty_sequence/input.json b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_with_empty_sequence/input.json new file mode 100644 index 000000000..4f6668222 --- /dev/null +++ b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_with_empty_sequence/input.json @@ -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": ":" + } + } + } + } +} diff --git a/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_with_empty_sequence/output.json b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_with_empty_sequence/output.json new file mode 100644 index 000000000..acf3b74ef --- /dev/null +++ b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_with_empty_sequence/output.json @@ -0,0 +1,9 @@ +{ + "sources": + { + "A": + { + "id": 0 + } + } +} diff --git a/test/cmdlineTests/yul_optimizer_steps_invalid_nested_delimiter/args b/test/cmdlineTests/yul_optimizer_steps_invalid_nested_delimiter/args new file mode 100644 index 000000000..c7bdc6563 --- /dev/null +++ b/test/cmdlineTests/yul_optimizer_steps_invalid_nested_delimiter/args @@ -0,0 +1 @@ +--ir-optimized --optimize --yul-optimizations dhfo[Dg:vu]lfnTUtnIf diff --git a/test/cmdlineTests/yul_optimizer_steps_invalid_nested_delimiter/err b/test/cmdlineTests/yul_optimizer_steps_invalid_nested_delimiter/err new file mode 100644 index 000000000..cb7b570f1 --- /dev/null +++ b/test/cmdlineTests/yul_optimizer_steps_invalid_nested_delimiter/err @@ -0,0 +1 @@ +Invalid optimizer step sequence in --yul-optimizations: Cleanup delimiter may only be placed at nesting level zero diff --git a/test/cmdlineTests/yul_optimizer_steps_invalid_nested_delimiter/exit b/test/cmdlineTests/yul_optimizer_steps_invalid_nested_delimiter/exit new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/test/cmdlineTests/yul_optimizer_steps_invalid_nested_delimiter/exit @@ -0,0 +1 @@ +1 diff --git a/test/cmdlineTests/yul_optimizer_steps_invalid_nested_delimiter/input.sol b/test/cmdlineTests/yul_optimizer_steps_invalid_nested_delimiter/input.sol new file mode 100644 index 000000000..0279d3b7d --- /dev/null +++ b/test/cmdlineTests/yul_optimizer_steps_invalid_nested_delimiter/input.sol @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity >=0.0; + +contract C +{ + function f() public pure {} +} diff --git a/test/cmdlineTests/yul_optimizer_steps_multiple_delimiters/args b/test/cmdlineTests/yul_optimizer_steps_multiple_delimiters/args new file mode 100644 index 000000000..4214dbbd1 --- /dev/null +++ b/test/cmdlineTests/yul_optimizer_steps_multiple_delimiters/args @@ -0,0 +1 @@ +--ir-optimized --optimize --yul-optimizations dhfoDg:vulfn:TUtnIf diff --git a/test/cmdlineTests/yul_optimizer_steps_multiple_delimiters/err b/test/cmdlineTests/yul_optimizer_steps_multiple_delimiters/err new file mode 100644 index 000000000..70b1b2c21 --- /dev/null +++ b/test/cmdlineTests/yul_optimizer_steps_multiple_delimiters/err @@ -0,0 +1 @@ +Invalid optimizer step sequence in --yul-optimizations: Too many colon delimiters diff --git a/test/cmdlineTests/yul_optimizer_steps_multiple_delimiters/exit b/test/cmdlineTests/yul_optimizer_steps_multiple_delimiters/exit new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/test/cmdlineTests/yul_optimizer_steps_multiple_delimiters/exit @@ -0,0 +1 @@ +1 diff --git a/test/cmdlineTests/yul_optimizer_steps_multiple_delimiters/input.sol b/test/cmdlineTests/yul_optimizer_steps_multiple_delimiters/input.sol new file mode 100644 index 000000000..0279d3b7d --- /dev/null +++ b/test/cmdlineTests/yul_optimizer_steps_multiple_delimiters/input.sol @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity >=0.0; + +contract C +{ + function f() public pure {} +} diff --git a/test/cmdlineTests/yul_optimizer_steps_short_sequence/args b/test/cmdlineTests/yul_optimizer_steps_short_sequence/args new file mode 100644 index 000000000..ba2f47ebe --- /dev/null +++ b/test/cmdlineTests/yul_optimizer_steps_short_sequence/args @@ -0,0 +1 @@ +--ir-optimized --optimize --yul-optimizations iDu diff --git a/test/cmdlineTests/yul_optimizer_steps_short_sequence/input.sol b/test/cmdlineTests/yul_optimizer_steps_short_sequence/input.sol new file mode 100644 index 000000000..2d82716f0 --- /dev/null +++ b/test/cmdlineTests/yul_optimizer_steps_short_sequence/input.sol @@ -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) + } + } +} diff --git a/test/cmdlineTests/yul_optimizer_steps_short_sequence/output b/test/cmdlineTests/yul_optimizer_steps_short_sequence/output new file mode 100644 index 000000000..0a4a2c5a2 --- /dev/null +++ b/test/cmdlineTests/yul_optimizer_steps_short_sequence/output @@ -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"" + } +} diff --git a/test/cmdlineTests/yul_optimizer_steps_with_cleanup_sequence/args b/test/cmdlineTests/yul_optimizer_steps_with_cleanup_sequence/args new file mode 100644 index 000000000..872a81048 --- /dev/null +++ b/test/cmdlineTests/yul_optimizer_steps_with_cleanup_sequence/args @@ -0,0 +1 @@ +--ir-optimized --optimize --yul-optimizations dhfoDgvulfnTUtnIf:fDnTOc diff --git a/test/cmdlineTests/yul_optimizer_steps_with_cleanup_sequence/input.sol b/test/cmdlineTests/yul_optimizer_steps_with_cleanup_sequence/input.sol new file mode 100644 index 000000000..ab0d98d67 --- /dev/null +++ b/test/cmdlineTests/yul_optimizer_steps_with_cleanup_sequence/input.sol @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity >=0.0; +pragma abicoder v2; + +contract C +{ + constructor() {} +} diff --git a/test/cmdlineTests/yul_optimizer_steps_with_cleanup_sequence/output b/test/cmdlineTests/yul_optimizer_steps_with_cleanup_sequence/output new file mode 100644 index 000000000..32c0eba2e --- /dev/null +++ b/test/cmdlineTests/yul_optimizer_steps_with_cleanup_sequence/output @@ -0,0 +1,34 @@ +Optimized IR: +/// @use-src 0:"yul_optimizer_steps_with_cleanup_sequence/input.sol" +object "C_7" { + code { + { + /// @src 0:80:115 "contract C..." + mstore(64, memoryguard(0x80)) + if callvalue() + { + revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() + } + let _1 := allocate_unbounded() + codecopy(_1, dataoffset("C_7_deployed"), datasize("C_7_deployed")) + return(_1, datasize("C_7_deployed")) + } + function allocate_unbounded() -> memPtr + { memPtr := mload(64) } + function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() + { revert(0, 0) } + } + /// @use-src 0:"yul_optimizer_steps_with_cleanup_sequence/input.sol" + object "C_7_deployed" { + code { + { + /// @src 0:80:115 "contract C..." + mstore(64, memoryguard(0x80)) + revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() + } + function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() + { revert(0, 0) } + } + data ".metadata" hex"" + } +} diff --git a/test/cmdlineTests/yul_optimizer_steps_with_empty_cleanup_sequence/args b/test/cmdlineTests/yul_optimizer_steps_with_empty_cleanup_sequence/args new file mode 100644 index 000000000..6673a776a --- /dev/null +++ b/test/cmdlineTests/yul_optimizer_steps_with_empty_cleanup_sequence/args @@ -0,0 +1 @@ +--ir-optimized --optimize --yul-optimizations iDu: diff --git a/test/cmdlineTests/yul_optimizer_steps_with_empty_cleanup_sequence/input.sol b/test/cmdlineTests/yul_optimizer_steps_with_empty_cleanup_sequence/input.sol new file mode 100644 index 000000000..2d82716f0 --- /dev/null +++ b/test/cmdlineTests/yul_optimizer_steps_with_empty_cleanup_sequence/input.sol @@ -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) + } + } +} diff --git a/test/cmdlineTests/yul_optimizer_steps_with_empty_cleanup_sequence/output b/test/cmdlineTests/yul_optimizer_steps_with_empty_cleanup_sequence/output new file mode 100644 index 000000000..3f865bfe5 --- /dev/null +++ b/test/cmdlineTests/yul_optimizer_steps_with_empty_cleanup_sequence/output @@ -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:221 "contract C {..." + mstore(64, memoryguard(0x80)) + /// @src 0:129:213 "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:221 "contract C {..." + mstore(64, memoryguard(0x80)) + revert(0, 0) + } + } + data ".metadata" hex"" + } +} diff --git a/test/cmdlineTests/yul_optimizer_steps_with_empty_optimization_sequence/args b/test/cmdlineTests/yul_optimizer_steps_with_empty_optimization_sequence/args new file mode 100644 index 000000000..b5d1d3c65 --- /dev/null +++ b/test/cmdlineTests/yul_optimizer_steps_with_empty_optimization_sequence/args @@ -0,0 +1 @@ +--ir-optimized --optimize --yul-optimizations :iDu diff --git a/test/cmdlineTests/yul_optimizer_steps_with_empty_optimization_sequence/input.sol b/test/cmdlineTests/yul_optimizer_steps_with_empty_optimization_sequence/input.sol new file mode 100644 index 000000000..2d82716f0 --- /dev/null +++ b/test/cmdlineTests/yul_optimizer_steps_with_empty_optimization_sequence/input.sol @@ -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) + } + } +} diff --git a/test/cmdlineTests/yul_optimizer_steps_with_empty_optimization_sequence/output b/test/cmdlineTests/yul_optimizer_steps_with_empty_optimization_sequence/output new file mode 100644 index 000000000..9685b4312 --- /dev/null +++ b/test/cmdlineTests/yul_optimizer_steps_with_empty_optimization_sequence/output @@ -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:221 "contract C {..." + mstore(64, memoryguard(0x80)) + /// @src 0:129:213 "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:221 "contract C {..." + mstore(64, memoryguard(0x80)) + revert(0, 0) + } + } + data ".metadata" hex"" + } +} diff --git a/test/cmdlineTests/yul_optimizer_steps_with_empty_sequences/args b/test/cmdlineTests/yul_optimizer_steps_with_empty_sequences/args new file mode 100644 index 000000000..d1f01a72f --- /dev/null +++ b/test/cmdlineTests/yul_optimizer_steps_with_empty_sequences/args @@ -0,0 +1 @@ +--ir-optimized --optimize --yul-optimizations : diff --git a/test/cmdlineTests/yul_optimizer_steps_with_empty_sequences/input.sol b/test/cmdlineTests/yul_optimizer_steps_with_empty_sequences/input.sol new file mode 100644 index 000000000..ab0d98d67 --- /dev/null +++ b/test/cmdlineTests/yul_optimizer_steps_with_empty_sequences/input.sol @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity >=0.0; +pragma abicoder v2; + +contract C +{ + constructor() {} +} diff --git a/test/cmdlineTests/yul_optimizer_steps_with_empty_sequences/output b/test/cmdlineTests/yul_optimizer_steps_with_empty_sequences/output new file mode 100644 index 000000000..35ef9ca0b --- /dev/null +++ b/test/cmdlineTests/yul_optimizer_steps_with_empty_sequences/output @@ -0,0 +1,42 @@ +Optimized IR: +/// @use-src 0:"yul_optimizer_steps_with_empty_sequences/input.sol" +object "C_7" { + code { + { + /// @src 0:80:115 "contract C..." + mstore(64, memoryguard(0x80)) + if callvalue() + { + revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() + } + constructor_C() + let _1 := allocate_unbounded() + codecopy(_1, dataoffset("C_7_deployed"), datasize("C_7_deployed")) + return(_1, datasize("C_7_deployed")) + } + function allocate_unbounded() -> memPtr + { memPtr := mload(64) } + function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() + { revert(0, 0) } + /// @ast-id 6 @src 0:97:113 "constructor() {}" + function constructor_C() + { } + } + /// @use-src 0:"yul_optimizer_steps_with_empty_sequences/input.sol" + object "C_7_deployed" { + code { + { + /// @src 0:80:115 "contract C..." + mstore(64, memoryguard(0x80)) + revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() + } + function shift_right_unsigned(value) -> newValue + { newValue := shr(224, value) } + function allocate_unbounded() -> memPtr + { memPtr := mload(64) } + function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() + { revert(0, 0) } + } + data ".metadata" hex"" + } +} diff --git a/test/libyul/YulOptimizerTestCommon.cpp b/test/libyul/YulOptimizerTestCommon.cpp index 60826665a..7623efc12 100644 --- a/test/libyul/YulOptimizerTestCommon.cpp +++ b/test/libyul/YulOptimizerTestCommon.cpp @@ -339,6 +339,7 @@ YulOptimizerTestCommon::YulOptimizerTestCommon( *m_object, true, frontend::OptimiserSettings::DefaultYulOptimiserSteps, + frontend::OptimiserSettings::DefaultYulOptimiserCleanupSteps, frontend::OptimiserSettings::standard().expectedExecutionsPerDeployment ); }}, From ddf0d784ac9888a59200e242e130334c5b8a3e17 Mon Sep 17 00:00:00 2001 From: Nikola Matic Date: Fri, 12 Aug 2022 12:51:16 +0200 Subject: [PATCH 2/5] Changelog and docs --- Changelog.md | 4 ++-- docs/internals/optimizer.rst | 6 +++++- docs/yul.rst | 8 +++++++- .../input.sol | 1 + .../output | 6 +++--- .../input.sol | 1 + .../output | 6 +++--- 7 files changed, 22 insertions(+), 10 deletions(-) diff --git a/Changelog.md b/Changelog.md index 0e45c2ea5..a18af9e68 100644 --- a/Changelog.md +++ b/Changelog.md @@ -4,7 +4,7 @@ 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. Bugfixes: @@ -21,7 +21,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. diff --git a/docs/internals/optimizer.rst b/docs/internals/optimizer.rst index 3c12f0adf..6650e79b5 100644 --- a/docs/internals/optimizer.rst +++ b/docs/internals/optimizer.rst @@ -329,11 +329,15 @@ the ``--yul-optimizations`` option: .. code-block:: bash - solc --optimize --ir-optimized --yul-optimizations 'dhfoD[xarrscLMcCTU]uljmul' + 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 `. Preprocessing diff --git a/docs/yul.rst b/docs/yul.rst index 7ce010169..df409a3ac 100644 --- a/docs/yul.rst +++ b/docs/yul.rst @@ -1250,7 +1250,7 @@ You can override this sequence and supply your own using the ``--yul-optimizatio .. code-block:: sh - 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 @@ -1259,6 +1259,12 @@ By enclosing part of the sequence in square brackets (``[]``) you tell the optim 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 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. + + The following optimization steps are available: ============ =============================== diff --git a/test/cmdlineTests/yul_optimizer_steps_with_empty_cleanup_sequence/input.sol b/test/cmdlineTests/yul_optimizer_steps_with_empty_cleanup_sequence/input.sol index 2d82716f0..45fec390e 100644 --- a/test/cmdlineTests/yul_optimizer_steps_with_empty_cleanup_sequence/input.sol +++ b/test/cmdlineTests/yul_optimizer_steps_with_empty_cleanup_sequence/input.sol @@ -7,6 +7,7 @@ contract C { assembly ("memory-safe") { let a := 0 revert(0, a) + // Without the cleanup sequence this will not be simplified to ``revert(a, a)``. } } } diff --git a/test/cmdlineTests/yul_optimizer_steps_with_empty_cleanup_sequence/output b/test/cmdlineTests/yul_optimizer_steps_with_empty_cleanup_sequence/output index 3f865bfe5..01641c53b 100644 --- a/test/cmdlineTests/yul_optimizer_steps_with_empty_cleanup_sequence/output +++ b/test/cmdlineTests/yul_optimizer_steps_with_empty_cleanup_sequence/output @@ -3,9 +3,9 @@ Optimized IR: object "C_8" { code { { - /// @src 0:80:221 "contract C {..." + /// @src 0:80:314 "contract C {..." mstore(64, memoryguard(0x80)) - /// @src 0:129:213 "assembly (\"memory-safe\") {..." + /// @src 0:129:306 "assembly (\"memory-safe\") {..." let usr$a := 0 revert(0, usr$a) } @@ -14,7 +14,7 @@ object "C_8" { object "C_8_deployed" { code { { - /// @src 0:80:221 "contract C {..." + /// @src 0:80:314 "contract C {..." mstore(64, memoryguard(0x80)) revert(0, 0) } diff --git a/test/cmdlineTests/yul_optimizer_steps_with_empty_optimization_sequence/input.sol b/test/cmdlineTests/yul_optimizer_steps_with_empty_optimization_sequence/input.sol index 2d82716f0..45fec390e 100644 --- a/test/cmdlineTests/yul_optimizer_steps_with_empty_optimization_sequence/input.sol +++ b/test/cmdlineTests/yul_optimizer_steps_with_empty_optimization_sequence/input.sol @@ -7,6 +7,7 @@ contract C { assembly ("memory-safe") { let a := 0 revert(0, a) + // Without the cleanup sequence this will not be simplified to ``revert(a, a)``. } } } diff --git a/test/cmdlineTests/yul_optimizer_steps_with_empty_optimization_sequence/output b/test/cmdlineTests/yul_optimizer_steps_with_empty_optimization_sequence/output index 9685b4312..b13e6e282 100644 --- a/test/cmdlineTests/yul_optimizer_steps_with_empty_optimization_sequence/output +++ b/test/cmdlineTests/yul_optimizer_steps_with_empty_optimization_sequence/output @@ -3,9 +3,9 @@ Optimized IR: object "C_8" { code { { - /// @src 0:80:221 "contract C {..." + /// @src 0:80:314 "contract C {..." mstore(64, memoryguard(0x80)) - /// @src 0:129:213 "assembly (\"memory-safe\") {..." + /// @src 0:129:306 "assembly (\"memory-safe\") {..." let usr$a := 0 revert(0, usr$a) } @@ -14,7 +14,7 @@ object "C_8" { object "C_8_deployed" { code { { - /// @src 0:80:221 "contract C {..." + /// @src 0:80:314 "contract C {..." mstore(64, memoryguard(0x80)) revert(0, 0) } From 314a1cc92fa6c91cf4b35bbfa5d51f4ec13f93ce Mon Sep 17 00:00:00 2001 From: Nikola Matic Date: Tue, 23 Aug 2022 11:58:12 +0200 Subject: [PATCH 3/5] Command line tests and minor touch ups --- docs/internals/optimizer.rst | 18 +------ docs/yul.rst | 27 +++++----- libsolidity/interface/CompilerStack.cpp | 1 + libsolidity/interface/OptimiserSettings.h | 7 ++- libsolidity/interface/StandardCompiler.cpp | 2 +- libyul/optimiser/Suite.cpp | 7 +-- solc/CommandLineParser.cpp | 2 +- .../output.json | 4 +- .../output.json | 4 +- .../err | 2 +- .../err | 2 +- .../input.sol | 2 +- .../input.sol | 2 +- test/libsolidity/StandardCompiler.cpp | 3 +- test/solc/CommandLineParser.cpp | 52 +++++++++++++++++++ 15 files changed, 88 insertions(+), 47 deletions(-) diff --git a/docs/internals/optimizer.rst b/docs/internals/optimizer.rst index 6650e79b5..b752a0766 100644 --- a/docs/internals/optimizer.rst +++ b/docs/internals/optimizer.rst @@ -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 `. +Detailed information regrading the optimization sequence as well a list of abbreviations is +available in the :ref:`Yul optimizer docs `. Preprocessing ------------- diff --git a/docs/yul.rst b/docs/yul.rst index df409a3ac..31180b432 100644 --- a/docs/yul.rst +++ b/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: diff --git a/libsolidity/interface/CompilerStack.cpp b/libsolidity/interface/CompilerStack.cpp index 702d5a0d2..167ef6e28 100644 --- a/libsolidity/interface/CompilerStack.cpp +++ b/libsolidity/interface/CompilerStack.cpp @@ -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); diff --git a/libsolidity/interface/OptimiserSettings.h b/libsolidity/interface/OptimiserSettings.h index 82324d3f7..bae343f2d 100644 --- a/libsolidity/interface/OptimiserSettings.h +++ b/libsolidity/interface/OptimiserSettings.h @@ -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. diff --git a/libsolidity/interface/StandardCompiler.cpp b/libsolidity/interface/StandardCompiler.cpp index 7ccb71d78..129ed845a 100644 --- a/libsolidity/interface/StandardCompiler.cpp +++ b/libsolidity/interface/StandardCompiler.cpp @@ -490,7 +490,7 @@ std::optional 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); diff --git a/libyul/optimiser/Suite.cpp b/libyul/optimiser/Suite.cpp index ae32b25c3..7b75ea966 100644 --- a/libyul/optimiser/Suite.cpp +++ b/libyul/optimiser/Suite.cpp @@ -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: { diff --git a/solc/CommandLineParser.cpp b/solc/CommandLineParser.cpp index ce2d4d044..18eef374c 100644 --- a/solc/CommandLineParser.cpp +++ b/solc/CommandLineParser.cpp @@ -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); diff --git a/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_invalid_nested_delimiter/output.json b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_invalid_nested_delimiter/output.json index 41c8a307f..f44ca7e2e 100644 --- a/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_invalid_nested_delimiter/output.json +++ b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_invalid_nested_delimiter/output.json @@ -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" } diff --git a/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_mutliple_delimiters/output.json b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_mutliple_delimiters/output.json index b6778a492..16cba14d7 100644 --- a/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_mutliple_delimiters/output.json +++ b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_mutliple_delimiters/output.json @@ -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" } diff --git a/test/cmdlineTests/yul_optimizer_steps_invalid_nested_delimiter/err b/test/cmdlineTests/yul_optimizer_steps_invalid_nested_delimiter/err index cb7b570f1..807212793 100644 --- a/test/cmdlineTests/yul_optimizer_steps_invalid_nested_delimiter/err +++ b/test/cmdlineTests/yul_optimizer_steps_invalid_nested_delimiter/err @@ -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 diff --git a/test/cmdlineTests/yul_optimizer_steps_multiple_delimiters/err b/test/cmdlineTests/yul_optimizer_steps_multiple_delimiters/err index 70b1b2c21..5aa76bd43 100644 --- a/test/cmdlineTests/yul_optimizer_steps_multiple_delimiters/err +++ b/test/cmdlineTests/yul_optimizer_steps_multiple_delimiters/err @@ -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 diff --git a/test/cmdlineTests/yul_optimizer_steps_with_empty_cleanup_sequence/input.sol b/test/cmdlineTests/yul_optimizer_steps_with_empty_cleanup_sequence/input.sol index 45fec390e..fc9ba5baf 100644 --- a/test/cmdlineTests/yul_optimizer_steps_with_empty_cleanup_sequence/input.sol +++ b/test/cmdlineTests/yul_optimizer_steps_with_empty_cleanup_sequence/input.sol @@ -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) } } } diff --git a/test/cmdlineTests/yul_optimizer_steps_with_empty_optimization_sequence/input.sol b/test/cmdlineTests/yul_optimizer_steps_with_empty_optimization_sequence/input.sol index 45fec390e..fc9ba5baf 100644 --- a/test/cmdlineTests/yul_optimizer_steps_with_empty_optimization_sequence/input.sol +++ b/test/cmdlineTests/yul_optimizer_steps_with_empty_optimization_sequence/input.sol @@ -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) } } } diff --git a/test/libsolidity/StandardCompiler.cpp b/test/libsolidity/StandardCompiler.cpp index 319a60885..9480e7049 100644 --- a/test/libsolidity/StandardCompiler.cpp +++ b/test/libsolidity/StandardCompiler.cpp @@ -1244,10 +1244,11 @@ BOOST_AUTO_TEST_CASE(optimizer_settings_details_different) BOOST_CHECK(optimizer["details"]["yulDetails"].isObject()); BOOST_CHECK( util::convertContainer>(optimizer["details"]["yulDetails"].getMemberNames()) == - (set{"stackAllocation", "optimizerSteps"}) + (set{"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); } diff --git a/test/solc/CommandLineParser.cpp b/test/solc/CommandLineParser.cpp index 47eda71ad..74cb79cd6 100644 --- a/test/solc/CommandLineParser.cpp +++ b/test/solc/CommandLineParser.cpp @@ -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 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> 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 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 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 From feba1bfeffc224eab781cc165091b750553bec28 Mon Sep 17 00:00:00 2001 From: Nikola Matic Date: Mon, 5 Sep 2022 09:52:17 +0200 Subject: [PATCH 4/5] Rework metadata and cover with tests --- libsolidity/interface/CompilerStack.cpp | 3 +- test/libsolidity/Metadata.cpp | 49 +++++++++++++++++++++++++ test/libsolidity/StandardCompiler.cpp | 6 +-- 3 files changed, 53 insertions(+), 5 deletions(-) diff --git a/libsolidity/interface/CompilerStack.cpp b/libsolidity/interface/CompilerStack.cpp index 167ef6e28..109650130 100644 --- a/libsolidity/interface/CompilerStack.cpp +++ b/libsolidity/interface/CompilerStack.cpp @@ -1539,8 +1539,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; + details["yulDetails"]["optimizerSteps"] = m_optimiserSettings.yulOptimiserSteps + ":" + m_optimiserSettings.yulOptimiserCleanupSteps; } meta["settings"]["optimizer"]["details"] = std::move(details); diff --git a/test/libsolidity/Metadata.cpp b/test/libsolidity/Metadata.cpp index 9cbf73f84..ea13286f1 100644 --- a/test/libsolidity/Metadata.cpp +++ b/test/libsolidity/Metadata.cpp @@ -400,6 +400,55 @@ BOOST_AUTO_TEST_CASE(metadata_revert_strings) BOOST_CHECK_EQUAL(metadata["settings"]["debug"]["revertStrings"], "strip"); } +BOOST_AUTO_TEST_CASE(metadata_optimiser_sequence) +{ + char const* sourceCode = R"( + pragma solidity >=0.0; + contract test { + } + )"; + + vector> sequences = + { + // { "", "" } + { "", "" }, + { "", "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("test"); + 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) { char const* sourceCode = R"( diff --git a/test/libsolidity/StandardCompiler.cpp b/test/libsolidity/StandardCompiler.cpp index 9480e7049..c2011e409 100644 --- a/test/libsolidity/StandardCompiler.cpp +++ b/test/libsolidity/StandardCompiler.cpp @@ -1244,11 +1244,11 @@ BOOST_AUTO_TEST_CASE(optimizer_settings_details_different) BOOST_CHECK(optimizer["details"]["yulDetails"].isObject()); BOOST_CHECK( util::convertContainer>(optimizer["details"]["yulDetails"].getMemberNames()) == - (set{"stackAllocation", "optimizerSteps", "optimizerCleanupSteps"}) + (set{"stackAllocation", "optimizerSteps"}) ); 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(optimizer["details"]["yulDetails"]["optimizerSteps"].asString() == + string{OptimiserSettings::DefaultYulOptimiserSteps} + ":" + string{OptimiserSettings::DefaultYulOptimiserCleanupSteps}); BOOST_CHECK_EQUAL(optimizer["details"].getMemberNames().size(), 9); BOOST_CHECK(optimizer["runs"].asUInt() == 600); } From e37dc8e9751f483e6ffe962dc7d9b739fecaf9b1 Mon Sep 17 00:00:00 2001 From: Nikola Matic Date: Mon, 12 Sep 2022 10:57:02 +0200 Subject: [PATCH 5/5] Address review comments --- Changelog.md | 5 +- docs/internals/optimizer.rst | 103 ++++++++++++------ docs/yul.rst | 68 +----------- libsolidity/interface/StandardCompiler.cpp | 2 + libyul/optimiser/Suite.cpp | 5 +- solc/CommandLineParser.cpp | 2 + .../args | 1 - .../err | 1 - .../exit | 1 - .../input.sol | 7 -- .../args | 1 - .../err | 1 - .../exit | 1 - .../input.sol | 7 -- .../args | 1 - .../input.sol | 8 -- .../output | 34 ------ .../args | 1 - .../input.sol | 8 -- .../output | 42 ------- test/libsolidity/Metadata.cpp | 24 ++-- test/libsolidity/StandardCompiler.cpp | 6 +- test/solc/CommandLineParser.cpp | 22 ++-- 23 files changed, 108 insertions(+), 243 deletions(-) delete mode 100644 test/cmdlineTests/yul_optimizer_steps_invalid_nested_delimiter/args delete mode 100644 test/cmdlineTests/yul_optimizer_steps_invalid_nested_delimiter/err delete mode 100644 test/cmdlineTests/yul_optimizer_steps_invalid_nested_delimiter/exit delete mode 100644 test/cmdlineTests/yul_optimizer_steps_invalid_nested_delimiter/input.sol delete mode 100644 test/cmdlineTests/yul_optimizer_steps_multiple_delimiters/args delete mode 100644 test/cmdlineTests/yul_optimizer_steps_multiple_delimiters/err delete mode 100644 test/cmdlineTests/yul_optimizer_steps_multiple_delimiters/exit delete mode 100644 test/cmdlineTests/yul_optimizer_steps_multiple_delimiters/input.sol delete mode 100644 test/cmdlineTests/yul_optimizer_steps_with_cleanup_sequence/args delete mode 100644 test/cmdlineTests/yul_optimizer_steps_with_cleanup_sequence/input.sol delete mode 100644 test/cmdlineTests/yul_optimizer_steps_with_cleanup_sequence/output delete mode 100644 test/cmdlineTests/yul_optimizer_steps_with_empty_sequences/args delete mode 100644 test/cmdlineTests/yul_optimizer_steps_with_empty_sequences/input.sol delete mode 100644 test/cmdlineTests/yul_optimizer_steps_with_empty_sequences/output diff --git a/Changelog.md b/Changelog.md index a18af9e68..84aa53023 100644 --- a/Changelog.md +++ b/Changelog.md @@ -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: @@ -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. diff --git a/docs/internals/optimizer.rst b/docs/internals/optimizer.rst index b752a0766..c9d10a8f6 100644 --- a/docs/internals/optimizer.rst +++ b/docs/internals/optimizer.rst @@ -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 `. +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 ------------- diff --git a/docs/yul.rst b/docs/yul.rst index 31180b432..f6109a125 100644 --- a/docs/yul.rst +++ b/docs/yul.rst @@ -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 `. .. _erc20yul: diff --git a/libsolidity/interface/StandardCompiler.cpp b/libsolidity/interface/StandardCompiler.cpp index 129ed845a..0af55df16 100644 --- a/libsolidity/interface/StandardCompiler.cpp +++ b/libsolidity/interface/StandardCompiler.cpp @@ -496,6 +496,8 @@ std::optional 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"); diff --git a/libyul/optimiser/Suite.cpp b/libyul/optimiser/Suite.cpp index 7b75ea966..c71a44001 100644 --- a/libyul/optimiser/Suite.cpp +++ b/libyul/optimiser/Suite.cpp @@ -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) @@ -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: { diff --git a/solc/CommandLineParser.cpp b/solc/CommandLineParser.cpp index 18eef374c..c6ddfec67 100644 --- a/solc/CommandLineParser.cpp +++ b/solc/CommandLineParser.cpp @@ -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; diff --git a/test/cmdlineTests/yul_optimizer_steps_invalid_nested_delimiter/args b/test/cmdlineTests/yul_optimizer_steps_invalid_nested_delimiter/args deleted file mode 100644 index c7bdc6563..000000000 --- a/test/cmdlineTests/yul_optimizer_steps_invalid_nested_delimiter/args +++ /dev/null @@ -1 +0,0 @@ ---ir-optimized --optimize --yul-optimizations dhfo[Dg:vu]lfnTUtnIf diff --git a/test/cmdlineTests/yul_optimizer_steps_invalid_nested_delimiter/err b/test/cmdlineTests/yul_optimizer_steps_invalid_nested_delimiter/err deleted file mode 100644 index 807212793..000000000 --- a/test/cmdlineTests/yul_optimizer_steps_invalid_nested_delimiter/err +++ /dev/null @@ -1 +0,0 @@ -Invalid optimizer step sequence in --yul-optimizations: Cleanup sequence delimiter cannot be placed inside the brackets diff --git a/test/cmdlineTests/yul_optimizer_steps_invalid_nested_delimiter/exit b/test/cmdlineTests/yul_optimizer_steps_invalid_nested_delimiter/exit deleted file mode 100644 index d00491fd7..000000000 --- a/test/cmdlineTests/yul_optimizer_steps_invalid_nested_delimiter/exit +++ /dev/null @@ -1 +0,0 @@ -1 diff --git a/test/cmdlineTests/yul_optimizer_steps_invalid_nested_delimiter/input.sol b/test/cmdlineTests/yul_optimizer_steps_invalid_nested_delimiter/input.sol deleted file mode 100644 index 0279d3b7d..000000000 --- a/test/cmdlineTests/yul_optimizer_steps_invalid_nested_delimiter/input.sol +++ /dev/null @@ -1,7 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0 -pragma solidity >=0.0; - -contract C -{ - function f() public pure {} -} diff --git a/test/cmdlineTests/yul_optimizer_steps_multiple_delimiters/args b/test/cmdlineTests/yul_optimizer_steps_multiple_delimiters/args deleted file mode 100644 index 4214dbbd1..000000000 --- a/test/cmdlineTests/yul_optimizer_steps_multiple_delimiters/args +++ /dev/null @@ -1 +0,0 @@ ---ir-optimized --optimize --yul-optimizations dhfoDg:vulfn:TUtnIf diff --git a/test/cmdlineTests/yul_optimizer_steps_multiple_delimiters/err b/test/cmdlineTests/yul_optimizer_steps_multiple_delimiters/err deleted file mode 100644 index 5aa76bd43..000000000 --- a/test/cmdlineTests/yul_optimizer_steps_multiple_delimiters/err +++ /dev/null @@ -1 +0,0 @@ -Invalid optimizer step sequence in --yul-optimizations: Too many cleanup sequence delimiters diff --git a/test/cmdlineTests/yul_optimizer_steps_multiple_delimiters/exit b/test/cmdlineTests/yul_optimizer_steps_multiple_delimiters/exit deleted file mode 100644 index d00491fd7..000000000 --- a/test/cmdlineTests/yul_optimizer_steps_multiple_delimiters/exit +++ /dev/null @@ -1 +0,0 @@ -1 diff --git a/test/cmdlineTests/yul_optimizer_steps_multiple_delimiters/input.sol b/test/cmdlineTests/yul_optimizer_steps_multiple_delimiters/input.sol deleted file mode 100644 index 0279d3b7d..000000000 --- a/test/cmdlineTests/yul_optimizer_steps_multiple_delimiters/input.sol +++ /dev/null @@ -1,7 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0 -pragma solidity >=0.0; - -contract C -{ - function f() public pure {} -} diff --git a/test/cmdlineTests/yul_optimizer_steps_with_cleanup_sequence/args b/test/cmdlineTests/yul_optimizer_steps_with_cleanup_sequence/args deleted file mode 100644 index 872a81048..000000000 --- a/test/cmdlineTests/yul_optimizer_steps_with_cleanup_sequence/args +++ /dev/null @@ -1 +0,0 @@ ---ir-optimized --optimize --yul-optimizations dhfoDgvulfnTUtnIf:fDnTOc diff --git a/test/cmdlineTests/yul_optimizer_steps_with_cleanup_sequence/input.sol b/test/cmdlineTests/yul_optimizer_steps_with_cleanup_sequence/input.sol deleted file mode 100644 index ab0d98d67..000000000 --- a/test/cmdlineTests/yul_optimizer_steps_with_cleanup_sequence/input.sol +++ /dev/null @@ -1,8 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0 -pragma solidity >=0.0; -pragma abicoder v2; - -contract C -{ - constructor() {} -} diff --git a/test/cmdlineTests/yul_optimizer_steps_with_cleanup_sequence/output b/test/cmdlineTests/yul_optimizer_steps_with_cleanup_sequence/output deleted file mode 100644 index 32c0eba2e..000000000 --- a/test/cmdlineTests/yul_optimizer_steps_with_cleanup_sequence/output +++ /dev/null @@ -1,34 +0,0 @@ -Optimized IR: -/// @use-src 0:"yul_optimizer_steps_with_cleanup_sequence/input.sol" -object "C_7" { - code { - { - /// @src 0:80:115 "contract C..." - mstore(64, memoryguard(0x80)) - if callvalue() - { - revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() - } - let _1 := allocate_unbounded() - codecopy(_1, dataoffset("C_7_deployed"), datasize("C_7_deployed")) - return(_1, datasize("C_7_deployed")) - } - function allocate_unbounded() -> memPtr - { memPtr := mload(64) } - function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() - { revert(0, 0) } - } - /// @use-src 0:"yul_optimizer_steps_with_cleanup_sequence/input.sol" - object "C_7_deployed" { - code { - { - /// @src 0:80:115 "contract C..." - mstore(64, memoryguard(0x80)) - revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() - } - function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() - { revert(0, 0) } - } - data ".metadata" hex"" - } -} diff --git a/test/cmdlineTests/yul_optimizer_steps_with_empty_sequences/args b/test/cmdlineTests/yul_optimizer_steps_with_empty_sequences/args deleted file mode 100644 index d1f01a72f..000000000 --- a/test/cmdlineTests/yul_optimizer_steps_with_empty_sequences/args +++ /dev/null @@ -1 +0,0 @@ ---ir-optimized --optimize --yul-optimizations : diff --git a/test/cmdlineTests/yul_optimizer_steps_with_empty_sequences/input.sol b/test/cmdlineTests/yul_optimizer_steps_with_empty_sequences/input.sol deleted file mode 100644 index ab0d98d67..000000000 --- a/test/cmdlineTests/yul_optimizer_steps_with_empty_sequences/input.sol +++ /dev/null @@ -1,8 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0 -pragma solidity >=0.0; -pragma abicoder v2; - -contract C -{ - constructor() {} -} diff --git a/test/cmdlineTests/yul_optimizer_steps_with_empty_sequences/output b/test/cmdlineTests/yul_optimizer_steps_with_empty_sequences/output deleted file mode 100644 index 35ef9ca0b..000000000 --- a/test/cmdlineTests/yul_optimizer_steps_with_empty_sequences/output +++ /dev/null @@ -1,42 +0,0 @@ -Optimized IR: -/// @use-src 0:"yul_optimizer_steps_with_empty_sequences/input.sol" -object "C_7" { - code { - { - /// @src 0:80:115 "contract C..." - mstore(64, memoryguard(0x80)) - if callvalue() - { - revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() - } - constructor_C() - let _1 := allocate_unbounded() - codecopy(_1, dataoffset("C_7_deployed"), datasize("C_7_deployed")) - return(_1, datasize("C_7_deployed")) - } - function allocate_unbounded() -> memPtr - { memPtr := mload(64) } - function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() - { revert(0, 0) } - /// @ast-id 6 @src 0:97:113 "constructor() {}" - function constructor_C() - { } - } - /// @use-src 0:"yul_optimizer_steps_with_empty_sequences/input.sol" - object "C_7_deployed" { - code { - { - /// @src 0:80:115 "contract C..." - mstore(64, memoryguard(0x80)) - revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() - } - function shift_right_unsigned(value) -> newValue - { newValue := shr(224, value) } - function allocate_unbounded() -> memPtr - { memPtr := mload(64) } - function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() - { revert(0, 0) } - } - data ".metadata" hex"" - } -} diff --git a/test/libsolidity/Metadata.cpp b/test/libsolidity/Metadata.cpp index ea13286f1..a5383b544 100644 --- a/test/libsolidity/Metadata.cpp +++ b/test/libsolidity/Metadata.cpp @@ -404,25 +404,25 @@ BOOST_AUTO_TEST_CASE(metadata_optimiser_sequence) { char const* sourceCode = R"( pragma solidity >=0.0; - contract test { + contract C { } )"; vector> sequences = { - // { "", "" } - { "", "" }, - { "", "fDn" }, - { "dhfoDgvulfnTUtnIf", "" }, - { "dhfoDgvulfnTUtnIf", "fDn" } + // {"", ""} + {"", ""}, + {"", "fDn"}, + {"dhfoDgvulfnTUtnIf", "" }, + {"dhfoDgvulfnTUtnIf", "fDn"} }; - auto check = [sourceCode](string const& optimizerSequence, string const& optimizerCleanupSequence) + auto check = [sourceCode](string const& _optimizerSequence, string const& _optimizerCleanupSequence) { OptimiserSettings optimizerSettings = OptimiserSettings::minimal(); optimizerSettings.runYulOptimiser = true; - optimizerSettings.yulOptimiserSteps = optimizerSequence; - optimizerSettings.yulOptimiserCleanupSteps = optimizerCleanupSequence; + optimizerSettings.yulOptimiserSteps = _optimizerSequence; + optimizerSettings.yulOptimiserCleanupSteps = _optimizerCleanupSequence; CompilerStack compilerStack; compilerStack.setSources({{"", std::string(sourceCode)}}); compilerStack.setEVMVersion(solidity::test::CommonOptions::get().evmVersion()); @@ -430,7 +430,7 @@ BOOST_AUTO_TEST_CASE(metadata_optimiser_sequence) BOOST_REQUIRE_MESSAGE(compilerStack.compile(), "Compiling contract failed"); - std::string const& serialisedMetadata = compilerStack.metadata("test"); + std::string const& serialisedMetadata = compilerStack.metadata("C"); Json::Value metadata; BOOST_REQUIRE(util::jsonParseStrict(serialisedMetadata, metadata)); BOOST_CHECK(solidity::test::isValidMetadata(metadata)); @@ -439,14 +439,12 @@ BOOST_AUTO_TEST_CASE(metadata_optimiser_sequence) BOOST_CHECK(metadata["settings"]["optimizer"]["details"]["yulDetails"].isMember("optimizerSteps")); string const metadataOptimizerSteps = metadata["settings"]["optimizer"]["details"]["yulDetails"]["optimizerSteps"].asString(); - string const expectedMetadataOptimiserSteps = optimizerSequence + ":" + optimizerCleanupSequence; + 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) diff --git a/test/libsolidity/StandardCompiler.cpp b/test/libsolidity/StandardCompiler.cpp index c2011e409..54c12d30c 100644 --- a/test/libsolidity/StandardCompiler.cpp +++ b/test/libsolidity/StandardCompiler.cpp @@ -1247,8 +1247,10 @@ BOOST_AUTO_TEST_CASE(optimizer_settings_details_different) (set{"stackAllocation", "optimizerSteps"}) ); BOOST_CHECK(optimizer["details"]["yulDetails"]["stackAllocation"].asBool() == true); - BOOST_CHECK(optimizer["details"]["yulDetails"]["optimizerSteps"].asString() == - string{OptimiserSettings::DefaultYulOptimiserSteps} + ":" + string{OptimiserSettings::DefaultYulOptimiserCleanupSteps}); + BOOST_CHECK( + optimizer["details"]["yulDetails"]["optimizerSteps"].asString() == + OptimiserSettings::DefaultYulOptimiserSteps + ":"s + OptimiserSettings::DefaultYulOptimiserCleanupSteps + ); BOOST_CHECK_EQUAL(optimizer["details"].getMemberNames().size(), 9); BOOST_CHECK(optimizer["runs"].asUInt() == 600); } diff --git a/test/solc/CommandLineParser.cpp b/test/solc/CommandLineParser.cpp index 74cb79cd6..f2d020ae7 100644 --- a/test/solc/CommandLineParser.cpp +++ b/test/solc/CommandLineParser.cpp @@ -428,7 +428,7 @@ BOOST_AUTO_TEST_CASE(invalid_options_input_modes_combinations) BOOST_AUTO_TEST_CASE(default_optimiser_sequence) { - auto const& commandLineOptions = parseCommandLine({"solc", "contract.sol", "--optimize"}); + CommandLineOptions const& commandLineOptions = parseCommandLine({"solc", "contract.sol", "--optimize"}); BOOST_CHECK_EQUAL(commandLineOptions.optimiserSettings().yulOptimiserSteps, OptimiserSettings::DefaultYulOptimiserSteps); BOOST_CHECK_EQUAL(commandLineOptions.optimiserSettings().yulOptimiserCleanupSteps, OptimiserSettings::DefaultYulOptimiserCleanupSteps); } @@ -436,26 +436,26 @@ BOOST_AUTO_TEST_CASE(default_optimiser_sequence) BOOST_AUTO_TEST_CASE(valid_optimiser_sequences) { vector 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 + ":", // 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> expectedParsedSequences { - { "", "" }, - { "", "fDn"}, - { "dhfoDgvulfnTUtnIf", ""}, - { "dhfoDgvulfnTUtnIf", "fDn"}, - { "dhfo[Dgvulfn]TUtnIf", "f[D]n"} + {"", ""}, + {"", "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]}); + 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);