mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #8701 from ethereum/solc-yul-chromosome
solc option for selecting yul optimisations
This commit is contained in:
commit
61b1369fc2
@ -502,6 +502,7 @@ void CompilerContext::optimizeYul(yul::Object& _object, yul::EVMDialect const& _
|
||||
&meter,
|
||||
_object,
|
||||
_optimiserSettings.optimizeStackAllocation,
|
||||
_optimiserSettings.yulOptimiserSteps,
|
||||
_externalIdentifiers
|
||||
);
|
||||
|
||||
|
@ -1265,6 +1265,7 @@ string CompilerStack::createMetadata(Contract const& _contract) const
|
||||
{
|
||||
details["yulDetails"] = Json::objectValue;
|
||||
details["yulDetails"]["stackAllocation"] = m_optimiserSettings.optimizeStackAllocation;
|
||||
details["yulDetails"]["optimizerSteps"] = m_optimiserSettings.yulOptimiserSteps;
|
||||
}
|
||||
|
||||
meta["settings"]["optimizer"]["details"] = std::move(details);
|
||||
|
@ -23,12 +23,31 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
|
||||
namespace solidity::frontend
|
||||
{
|
||||
|
||||
struct OptimiserSettings
|
||||
{
|
||||
static char constexpr DefaultYulOptimiserSteps[] =
|
||||
"dhfoDgvulfnTUtnIf" // None of these can make stack problems worse
|
||||
"["
|
||||
"xarrscLM" // Turn into SSA and simplify
|
||||
"cCTUtTOntnfDIul" // Perform structural simplification
|
||||
"Lcul" // Simplify again
|
||||
"Vcul jj" // Reverse SSA
|
||||
|
||||
// should have good "compilability" property here.
|
||||
|
||||
"eul" // Run functional expression inliner
|
||||
"xarulrul" // Prune a bit more in SSA
|
||||
"xarrcL" // Turn into SSA again and simplify
|
||||
"gvif" // Run full inliner
|
||||
"CTUcarrLsTOtfDncarrIulc" // SSA plus simplify
|
||||
"]"
|
||||
"jmuljuljul VcTOcul jmul"; // Make source short and pretty
|
||||
|
||||
/// No optimisations at all - not recommended.
|
||||
static OptimiserSettings none()
|
||||
{
|
||||
@ -74,6 +93,7 @@ struct OptimiserSettings
|
||||
runConstantOptimiser == _other.runConstantOptimiser &&
|
||||
optimizeStackAllocation == _other.optimizeStackAllocation &&
|
||||
runYulOptimiser == _other.runYulOptimiser &&
|
||||
yulOptimiserSteps == _other.yulOptimiserSteps &&
|
||||
expectedExecutionsPerDeployment == _other.expectedExecutionsPerDeployment;
|
||||
}
|
||||
|
||||
@ -95,6 +115,11 @@ struct OptimiserSettings
|
||||
bool optimizeStackAllocation = false;
|
||||
/// Yul optimiser with default settings. Will only run on certain parts of the code for now.
|
||||
bool runYulOptimiser = false;
|
||||
/// Sequence of optimisation steps to be performed by Yul optimiser.
|
||||
/// Note that there are some hard-coded steps in the optimiser and you cannot disable
|
||||
/// them just by setting this to an empty string. Set @a runYulOptimiser to false if you want
|
||||
/// no optimisations.
|
||||
std::string yulOptimiserSteps = DefaultYulOptimiserSteps;
|
||||
/// 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;
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include <libsolidity/ast/ASTJsonConverter.h>
|
||||
#include <libyul/AssemblyStack.h>
|
||||
#include <libyul/Exceptions.h>
|
||||
#include <libyul/optimiser/Suite.h>
|
||||
#include <liblangutil/SourceReferenceFormatter.h>
|
||||
#include <libevmasm/Instruction.h>
|
||||
#include <libsolutil/JSON.h>
|
||||
@ -402,6 +403,33 @@ std::optional<Json::Value> checkOptimizerDetail(Json::Value const& _details, std
|
||||
return {};
|
||||
}
|
||||
|
||||
std::optional<Json::Value> checkOptimizerDetailSteps(Json::Value const& _details, std::string const& _name, string& _setting)
|
||||
{
|
||||
if (_details.isMember(_name))
|
||||
{
|
||||
if (_details[_name].isString())
|
||||
{
|
||||
try
|
||||
{
|
||||
yul::OptimiserSuite::validateSequence(_details[_name].asString());
|
||||
}
|
||||
catch (yul::OptimizerException const& _exception)
|
||||
{
|
||||
return formatFatalError(
|
||||
"JSONError",
|
||||
"Invalid optimizer step sequence in \"settings.optimizer.details." + _name + "\": " + _exception.what()
|
||||
);
|
||||
}
|
||||
|
||||
_setting = _details[_name].asString();
|
||||
}
|
||||
else
|
||||
return formatFatalError("JSONError", "\"settings.optimizer.details." + _name + "\" must be a string");
|
||||
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
std::optional<Json::Value> checkMetadataKeys(Json::Value const& _input)
|
||||
{
|
||||
if (_input.isObject())
|
||||
@ -511,10 +539,12 @@ boost::variant<OptimiserSettings, Json::Value> parseOptimizerSettings(Json::Valu
|
||||
if (!settings.runYulOptimiser)
|
||||
return formatFatalError("JSONError", "\"Providing yulDetails requires Yul optimizer to be enabled.");
|
||||
|
||||
if (auto result = checkKeys(details["yulDetails"], {"stackAllocation"}, "settings.optimizer.details.yulDetails"))
|
||||
if (auto result = checkKeys(details["yulDetails"], {"stackAllocation", "optimizerSteps"}, "settings.optimizer.details.yulDetails"))
|
||||
return *result;
|
||||
if (auto error = checkOptimizerDetail(details["yulDetails"], "stackAllocation", settings.optimizeStackAllocation))
|
||||
return *error;
|
||||
if (auto error = checkOptimizerDetailSteps(details["yulDetails"], "optimizerSteps", settings.yulOptimiserSteps))
|
||||
return *error;
|
||||
}
|
||||
}
|
||||
return { std::move(settings) };
|
||||
|
@ -183,7 +183,8 @@ void AssemblyStack::optimize(Object& _object, bool _isCreation)
|
||||
dialect,
|
||||
meter.get(),
|
||||
_object,
|
||||
m_optimiserSettings.optimizeStackAllocation
|
||||
m_optimiserSettings.optimizeStackAllocation,
|
||||
m_optimiserSettings.yulOptimiserSteps
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -67,6 +67,7 @@
|
||||
|
||||
#include <libsolutil/CommonData.h>
|
||||
|
||||
#include <boost/range/adaptor/map.hpp>
|
||||
#include <boost/range/algorithm_ext/erase.hpp>
|
||||
|
||||
using namespace std;
|
||||
@ -78,6 +79,7 @@ void OptimiserSuite::run(
|
||||
GasMeter const* _meter,
|
||||
Object& _object,
|
||||
bool _optimizeStackAllocation,
|
||||
string const& _optimisationSequence,
|
||||
set<YulString> const& _externallyUsedIdentifiers
|
||||
)
|
||||
{
|
||||
@ -93,25 +95,12 @@ void OptimiserSuite::run(
|
||||
|
||||
OptimiserSuite suite(_dialect, reservedIdentifiers, Debug::None, ast);
|
||||
|
||||
suite.runSequence(
|
||||
"dhfoDgvulfnTUtnIf" // None of these can make stack problems worse
|
||||
"("
|
||||
"xarrscLM" // Turn into SSA and simplify
|
||||
"cCTUtTOntnfDIul" // Perform structural simplification
|
||||
"Lcul" // Simplify again
|
||||
"Vcul jj" // Reverse SSA
|
||||
// Some steps depend on properties ensured by FunctionHoister, FunctionGrouper and
|
||||
// ForLoopInitRewriter. Run them first to be able to run arbitrary sequences safely.
|
||||
suite.runSequence("fgo", ast);
|
||||
|
||||
// should have good "compilability" property here.
|
||||
|
||||
"eul" // Run functional expression inliner
|
||||
"xarulrul" // Prune a bit more in SSA
|
||||
"xarrcL" // Turn into SSA again and simplify
|
||||
"gvif" // Run full inliner
|
||||
"CTUcarrLsTOtfDncarrIulc" // SSA plus simplify
|
||||
")"
|
||||
"jmuljuljul VcTOcul jmul", // Make source short and pretty
|
||||
ast
|
||||
);
|
||||
// Now the user-supplied part
|
||||
suite.runSequence(_optimisationSequence, ast);
|
||||
|
||||
// This is a tuning parameter, but actually just prevents infinite loops.
|
||||
size_t stackCompressorMaxIterations = 16;
|
||||
@ -235,6 +224,12 @@ map<string, char> const& OptimiserSuite::stepNameToAbbreviationMap()
|
||||
{VarDeclInitializer::name, 'd'},
|
||||
};
|
||||
yulAssert(lookupTable.size() == allSteps().size(), "");
|
||||
yulAssert((
|
||||
util::convertContainer<set<char>>(string(NonStepAbbreviations)) -
|
||||
util::convertContainer<set<char>>(lookupTable | boost::adaptors::map_values)
|
||||
).size() == string(NonStepAbbreviations).size(),
|
||||
"Step abbreviation conflicts with a character reserved for another syntactic element"
|
||||
);
|
||||
|
||||
return lookupTable;
|
||||
}
|
||||
@ -246,32 +241,44 @@ map<char, string> const& OptimiserSuite::stepAbbreviationToNameMap()
|
||||
return lookupTable;
|
||||
}
|
||||
|
||||
void OptimiserSuite::runSequence(string const& _stepAbbreviations, Block& _ast)
|
||||
void OptimiserSuite::validateSequence(string const& _stepAbbreviations)
|
||||
{
|
||||
string input = _stepAbbreviations;
|
||||
boost::remove_erase(input, ' ');
|
||||
boost::remove_erase(input, '\n');
|
||||
|
||||
bool insideLoop = false;
|
||||
for (char abbreviation: input)
|
||||
for (char abbreviation: _stepAbbreviations)
|
||||
switch (abbreviation)
|
||||
{
|
||||
case '(':
|
||||
assertThrow(!insideLoop, OptimizerException, "Nested parentheses not supported");
|
||||
case ' ':
|
||||
case '\n':
|
||||
break;
|
||||
case '[':
|
||||
assertThrow(!insideLoop, OptimizerException, "Nested brackets are not supported");
|
||||
insideLoop = true;
|
||||
break;
|
||||
case ')':
|
||||
assertThrow(insideLoop, OptimizerException, "Unbalanced parenthesis");
|
||||
case ']':
|
||||
assertThrow(insideLoop, OptimizerException, "Unbalanced brackets");
|
||||
insideLoop = false;
|
||||
break;
|
||||
default:
|
||||
yulAssert(
|
||||
string(NonStepAbbreviations).find(abbreviation) == string::npos,
|
||||
"Unhandled syntactic element in the abbreviation sequence"
|
||||
);
|
||||
assertThrow(
|
||||
stepAbbreviationToNameMap().find(abbreviation) != stepAbbreviationToNameMap().end(),
|
||||
OptimizerException,
|
||||
"Invalid optimisation step abbreviation"
|
||||
"'"s + abbreviation + "' is not a valid step abbreviation"
|
||||
);
|
||||
}
|
||||
assertThrow(!insideLoop, OptimizerException, "Unbalanced parenthesis");
|
||||
assertThrow(!insideLoop, OptimizerException, "Unbalanced brackets");
|
||||
}
|
||||
|
||||
void OptimiserSuite::runSequence(string const& _stepAbbreviations, Block& _ast)
|
||||
{
|
||||
validateSequence(_stepAbbreviations);
|
||||
|
||||
string input = _stepAbbreviations;
|
||||
boost::remove_erase(input, ' ');
|
||||
boost::remove_erase(input, '\n');
|
||||
|
||||
auto abbreviationsToSteps = [](string const& _sequence) -> vector<string>
|
||||
{
|
||||
@ -281,21 +288,21 @@ void OptimiserSuite::runSequence(string const& _stepAbbreviations, Block& _ast)
|
||||
return steps;
|
||||
};
|
||||
|
||||
// The sequence has now been validated and must consist of pairs of segments that look like this: `aaa(bbb)`
|
||||
// `aaa` or `(bbb)` can be empty. For example we consider a sequence like `fgo(aaf)Oo` to have
|
||||
// four segments, the last of which is an empty parenthesis.
|
||||
// The sequence has now been validated and must consist of pairs of segments that look like this: `aaa[bbb]`
|
||||
// `aaa` or `[bbb]` can be empty. For example we consider a sequence like `fgo[aaf]Oo` to have
|
||||
// four segments, the last of which is an empty bracket.
|
||||
size_t currentPairStart = 0;
|
||||
while (currentPairStart < input.size())
|
||||
{
|
||||
size_t openingParenthesis = input.find('(', currentPairStart);
|
||||
size_t closingParenthesis = input.find(')', openingParenthesis);
|
||||
size_t firstCharInside = (openingParenthesis == string::npos ? input.size() : openingParenthesis + 1);
|
||||
yulAssert((openingParenthesis == string::npos) == (closingParenthesis == string::npos), "");
|
||||
size_t openingBracket = input.find('[', currentPairStart);
|
||||
size_t closingBracket = input.find(']', openingBracket);
|
||||
size_t firstCharInside = (openingBracket == string::npos ? input.size() : openingBracket + 1);
|
||||
yulAssert((openingBracket == string::npos) == (closingBracket == string::npos), "");
|
||||
|
||||
runSequence(abbreviationsToSteps(input.substr(currentPairStart, openingParenthesis - currentPairStart)), _ast);
|
||||
runSequenceUntilStable(abbreviationsToSteps(input.substr(firstCharInside, closingParenthesis - firstCharInside)), _ast);
|
||||
runSequence(abbreviationsToSteps(input.substr(currentPairStart, openingBracket - currentPairStart)), _ast);
|
||||
runSequenceUntilStable(abbreviationsToSteps(input.substr(firstCharInside, closingBracket - firstCharInside)), _ast);
|
||||
|
||||
currentPairStart = (closingParenthesis == string::npos ? input.size() : closingParenthesis + 1);
|
||||
currentPairStart = (closingBracket == string::npos ? input.size() : closingBracket + 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -47,6 +47,10 @@ class OptimiserSuite
|
||||
public:
|
||||
static constexpr size_t MaxRounds = 12;
|
||||
|
||||
/// 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[]";
|
||||
|
||||
enum class Debug
|
||||
{
|
||||
None,
|
||||
@ -58,9 +62,14 @@ public:
|
||||
GasMeter const* _meter,
|
||||
Object& _object,
|
||||
bool _optimizeStackAllocation,
|
||||
std::string const& _optimisationSequence,
|
||||
std::set<YulString> const& _externallyUsedIdentifiers = {}
|
||||
);
|
||||
|
||||
/// Ensures that specified sequence of step abbreviations is well-formed and can be executed.
|
||||
/// @throw OptimizerException if the sequence is invalid
|
||||
static void validateSequence(std::string const& _stepAbbreviations);
|
||||
|
||||
void runSequence(std::vector<std::string> const& _steps, Block& _ast);
|
||||
void runSequence(std::string const& _stepAbbreviations, Block& _ast);
|
||||
void runSequenceUntilStable(
|
||||
|
@ -37,6 +37,7 @@
|
||||
#include <libsolidity/interface/StorageLayout.h>
|
||||
|
||||
#include <libyul/AssemblyStack.h>
|
||||
#include <libyul/optimiser/Suite.h>
|
||||
|
||||
#include <libevmasm/Instruction.h>
|
||||
#include <libevmasm/GasMeter.h>
|
||||
@ -145,6 +146,7 @@ static string const g_strOpcodes = "opcodes";
|
||||
static string const g_strOptimize = "optimize";
|
||||
static string const g_strOptimizeRuns = "optimize-runs";
|
||||
static string const g_strOptimizeYul = "optimize-yul";
|
||||
static string const g_strYulOptimizations = "yul-optimizations";
|
||||
static string const g_strOutputDir = "output-dir";
|
||||
static string const g_strOverwrite = "overwrite";
|
||||
static string const g_strRevertStrings = "revert-strings";
|
||||
@ -781,7 +783,6 @@ Allowed options)",
|
||||
"Import ASTs to be compiled, assumes input holds the AST in compact JSON format. "
|
||||
"Supported Inputs is the output of the --standard-json or the one produced by --combined-json ast,compact-format"
|
||||
)
|
||||
|
||||
(
|
||||
g_argAssemble.c_str(),
|
||||
"Switch to assembly mode, ignoring all options except --machine, --yul-dialect and --optimize and assumes input is assembly."
|
||||
@ -835,7 +836,12 @@ Allowed options)",
|
||||
"Lower values will optimize more for initial deployment cost, higher values will optimize more for high-frequency usage."
|
||||
)
|
||||
(g_strOptimizeYul.c_str(), "Legacy option, ignored. Use the general --optimize to enable Yul optimizer.")
|
||||
(g_strNoOptimizeYul.c_str(), "Disable Yul optimizer in Solidity.");
|
||||
(g_strNoOptimizeYul.c_str(), "Disable Yul optimizer in Solidity.")
|
||||
(
|
||||
g_strYulOptimizations.c_str(),
|
||||
po::value<string>()->value_name("steps"),
|
||||
"Forces yul optimizer to use the specified sequence of optimization steps instead of the built-in one."
|
||||
);
|
||||
desc.add(optimizerOptions);
|
||||
po::options_description outputComponents("Output Components");
|
||||
outputComponents.add_options()
|
||||
@ -1168,6 +1174,26 @@ bool CommandLineInterface::processInput()
|
||||
settings.expectedExecutionsPerDeployment = m_args[g_argOptimizeRuns].as<unsigned>();
|
||||
if (m_args.count(g_strNoOptimizeYul))
|
||||
settings.runYulOptimiser = false;
|
||||
if (m_args.count(g_strYulOptimizations))
|
||||
{
|
||||
if (!settings.runYulOptimiser)
|
||||
{
|
||||
serr() << "--" << g_strYulOptimizations << " is invalid if Yul optimizer is disabled" << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
yul::OptimiserSuite::validateSequence(m_args[g_strYulOptimizations].as<string>());
|
||||
}
|
||||
catch (yul::OptimizerException const& _exception)
|
||||
{
|
||||
serr() << "Invalid optimizer step sequence in --" << g_strYulOptimizations << ": " << _exception.what() << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
settings.yulOptimiserSteps = m_args[g_strYulOptimizations].as<string>();
|
||||
}
|
||||
settings.optimizeStackAllocation = settings.runYulOptimiser;
|
||||
m_compiler->setOptimiserSettings(settings);
|
||||
|
||||
|
@ -0,0 +1,21 @@
|
||||
{
|
||||
"language": "Solidity",
|
||||
"sources":
|
||||
{
|
||||
"A":
|
||||
{
|
||||
"content": "pragma solidity >=0.0; contract C { function f() public pure {} }"
|
||||
}
|
||||
},
|
||||
"settings":
|
||||
{
|
||||
"optimizer": {
|
||||
"details": {
|
||||
"yul": true,
|
||||
"yulDetails": {
|
||||
"optimizerSteps": "dhfoDgvulfnTUtnIf\n[ xarrscLM\n]\njmuljuljul VcTOcul jmul"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1 @@
|
||||
{"sources":{"A":{"id":0}}}
|
@ -0,0 +1,21 @@
|
||||
{
|
||||
"language": "Solidity",
|
||||
"sources":
|
||||
{
|
||||
"A":
|
||||
{
|
||||
"content": "pragma solidity >=0.0; contract C { function f() public pure {} }"
|
||||
}
|
||||
},
|
||||
"settings":
|
||||
{
|
||||
"optimizer": {
|
||||
"details": {
|
||||
"yul": true,
|
||||
"yulDetails": {
|
||||
"optimizerSteps": "abcdefg{hijklmno}pqr[st]uvwxyz"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1 @@
|
||||
{"errors":[{"component":"general","formattedMessage":"Invalid optimizer step sequence in \"settings.optimizer.details.optimizerSteps\": 'b' is not a valid step abbreviation","message":"Invalid optimizer step sequence in \"settings.optimizer.details.optimizerSteps\": 'b' is not a valid step abbreviation","severity":"error","type":"JSONError"}]}
|
@ -0,0 +1,21 @@
|
||||
{
|
||||
"language": "Solidity",
|
||||
"sources":
|
||||
{
|
||||
"A":
|
||||
{
|
||||
"content": "pragma solidity >=0.0; contract C { function f() public pure {} }"
|
||||
}
|
||||
},
|
||||
"settings":
|
||||
{
|
||||
"optimizer": {
|
||||
"details": {
|
||||
"yul": true,
|
||||
"yulDetails": {
|
||||
"optimizerSteps": "a[a][aa[aa]]a"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1 @@
|
||||
{"errors":[{"component":"general","formattedMessage":"Invalid optimizer step sequence in \"settings.optimizer.details.optimizerSteps\": Nested brackets are not supported","message":"Invalid optimizer step sequence in \"settings.optimizer.details.optimizerSteps\": Nested brackets are not supported","severity":"error","type":"JSONError"}]}
|
@ -0,0 +1,21 @@
|
||||
{
|
||||
"language": "Solidity",
|
||||
"sources":
|
||||
{
|
||||
"A":
|
||||
{
|
||||
"content": "pragma solidity >=0.0; contract C { function f() public pure {} }"
|
||||
}
|
||||
},
|
||||
"settings":
|
||||
{
|
||||
"optimizer": {
|
||||
"details": {
|
||||
"yul": true,
|
||||
"yulDetails": {
|
||||
"optimizerSteps": 42
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1 @@
|
||||
{"errors":[{"component":"general","formattedMessage":"\"settings.optimizer.details.optimizerSteps\" must be a string","message":"\"settings.optimizer.details.optimizerSteps\" must be a string","severity":"error","type":"JSONError"}]}
|
@ -0,0 +1,21 @@
|
||||
{
|
||||
"language": "Solidity",
|
||||
"sources":
|
||||
{
|
||||
"A":
|
||||
{
|
||||
"content": "pragma solidity >=0.0; contract C { function f() public pure {} }"
|
||||
}
|
||||
},
|
||||
"settings":
|
||||
{
|
||||
"optimizer": {
|
||||
"details": {
|
||||
"yul": true,
|
||||
"yulDetails": {
|
||||
"optimizerSteps": "a[a]["
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1 @@
|
||||
{"errors":[{"component":"general","formattedMessage":"Invalid optimizer step sequence in \"settings.optimizer.details.optimizerSteps\": Unbalanced brackets","message":"Invalid optimizer step sequence in \"settings.optimizer.details.optimizerSteps\": Unbalanced brackets","severity":"error","type":"JSONError"}]}
|
1
test/cmdlineTests/yul_optimizer_steps/args
Normal file
1
test/cmdlineTests/yul_optimizer_steps/args
Normal file
@ -0,0 +1 @@
|
||||
--ir-optimized --optimize --yul-optimizations dhfoDgvulfnTUtnIf
|
6
test/cmdlineTests/yul_optimizer_steps/input.sol
Normal file
6
test/cmdlineTests/yul_optimizer_steps/input.sol
Normal file
@ -0,0 +1,6 @@
|
||||
pragma solidity >=0.0;
|
||||
|
||||
contract C
|
||||
{
|
||||
constructor() public {}
|
||||
}
|
34
test/cmdlineTests/yul_optimizer_steps/output
Normal file
34
test/cmdlineTests/yul_optimizer_steps/output
Normal file
@ -0,0 +1,34 @@
|
||||
Optimized IR:
|
||||
/*******************************************************
|
||||
* WARNING *
|
||||
* Solidity to Yul compilation is still EXPERIMENTAL *
|
||||
* It can result in LOSS OF FUNDS or worse *
|
||||
* !USE AT YOUR OWN RISK! *
|
||||
*******************************************************/
|
||||
|
||||
object "C_6" {
|
||||
code {
|
||||
{
|
||||
mstore(64, 128)
|
||||
if callvalue() { revert(0, 0) }
|
||||
codecopy(0, dataoffset("C_6_deployed"), datasize("C_6_deployed"))
|
||||
return(0, datasize("C_6_deployed"))
|
||||
}
|
||||
}
|
||||
object "C_6_deployed" {
|
||||
code {
|
||||
{
|
||||
mstore(64, 128)
|
||||
if iszero(lt(calldatasize(), 4))
|
||||
{
|
||||
let selector := shift_right_224_unsigned(calldataload(0))
|
||||
pop(selector)
|
||||
}
|
||||
pop(iszero(calldatasize()))
|
||||
revert(0, 0)
|
||||
}
|
||||
function shift_right_224_unsigned(value) -> newValue
|
||||
{ newValue := shr(224, value) }
|
||||
}
|
||||
}
|
||||
}
|
1
test/cmdlineTests/yul_optimizer_steps_disabled/args
Normal file
1
test/cmdlineTests/yul_optimizer_steps_disabled/args
Normal file
@ -0,0 +1 @@
|
||||
--ir-optimized --yul-optimizations dhfoDgvulfnTUtnIf
|
1
test/cmdlineTests/yul_optimizer_steps_disabled/err
Normal file
1
test/cmdlineTests/yul_optimizer_steps_disabled/err
Normal file
@ -0,0 +1 @@
|
||||
--yul-optimizations is invalid if Yul optimizer is disabled
|
1
test/cmdlineTests/yul_optimizer_steps_disabled/exit
Normal file
1
test/cmdlineTests/yul_optimizer_steps_disabled/exit
Normal file
@ -0,0 +1 @@
|
||||
1
|
6
test/cmdlineTests/yul_optimizer_steps_disabled/input.sol
Normal file
6
test/cmdlineTests/yul_optimizer_steps_disabled/input.sol
Normal file
@ -0,0 +1,6 @@
|
||||
pragma solidity >=0.0;
|
||||
|
||||
contract C
|
||||
{
|
||||
function f() public pure {}
|
||||
}
|
@ -0,0 +1 @@
|
||||
--ir-optimized --optimize --yul-optimizations abcdefg{hijklmno}pqr[st]uvwxyz
|
@ -0,0 +1 @@
|
||||
Invalid optimizer step sequence in --yul-optimizations: 'b' is not a valid step abbreviation
|
@ -0,0 +1 @@
|
||||
1
|
@ -0,0 +1,6 @@
|
||||
pragma solidity >=0.0;
|
||||
|
||||
contract C
|
||||
{
|
||||
function f() public pure {}
|
||||
}
|
@ -0,0 +1 @@
|
||||
--ir-optimized --optimize --yul-optimizations a[a][aa[aa]]a
|
@ -0,0 +1 @@
|
||||
Invalid optimizer step sequence in --yul-optimizations: Nested brackets are not supported
|
@ -0,0 +1 @@
|
||||
1
|
@ -0,0 +1,6 @@
|
||||
pragma solidity >=0.0;
|
||||
|
||||
contract C
|
||||
{
|
||||
function f() public pure {}
|
||||
}
|
@ -0,0 +1 @@
|
||||
--ir-optimized --optimize --yul-optimizations a[a][
|
@ -0,0 +1 @@
|
||||
Invalid optimizer step sequence in --yul-optimizations: Unbalanced brackets
|
@ -0,0 +1 @@
|
||||
1
|
@ -0,0 +1,6 @@
|
||||
pragma solidity >=0.0;
|
||||
|
||||
contract C
|
||||
{
|
||||
function f() public pure {}
|
||||
}
|
@ -21,11 +21,15 @@
|
||||
|
||||
#include <string>
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#include <libsolidity/interface/OptimiserSettings.h>
|
||||
#include <libsolidity/interface/StandardCompiler.h>
|
||||
#include <libsolidity/interface/Version.h>
|
||||
#include <libsolutil/JSON.h>
|
||||
#include <libsolutil/CommonData.h>
|
||||
#include <test/Metadata.h>
|
||||
|
||||
#include <set>
|
||||
|
||||
using namespace std;
|
||||
using namespace solidity::evmasm;
|
||||
|
||||
@ -1058,8 +1062,12 @@ BOOST_AUTO_TEST_CASE(optimizer_settings_details_different)
|
||||
BOOST_CHECK(optimizer["details"]["peephole"].asBool() == true);
|
||||
BOOST_CHECK(optimizer["details"]["yul"].asBool() == true);
|
||||
BOOST_CHECK(optimizer["details"]["yulDetails"].isObject());
|
||||
BOOST_CHECK(optimizer["details"]["yulDetails"].getMemberNames() == vector<string>{"stackAllocation"});
|
||||
BOOST_CHECK(
|
||||
util::convertContainer<set<string>>(optimizer["details"]["yulDetails"].getMemberNames()) ==
|
||||
(set<string>{"stackAllocation", "optimizerSteps"})
|
||||
);
|
||||
BOOST_CHECK(optimizer["details"]["yulDetails"]["stackAllocation"].asBool() == true);
|
||||
BOOST_CHECK(optimizer["details"]["yulDetails"]["optimizerSteps"].asString() == OptimiserSettings::DefaultYulOptimiserSteps);
|
||||
BOOST_CHECK_EQUAL(optimizer["details"].getMemberNames().size(), 8);
|
||||
BOOST_CHECK(optimizer["runs"].asUInt() == 600);
|
||||
}
|
||||
|
@ -74,6 +74,8 @@
|
||||
|
||||
#include <libsolutil/AnsiColorized.h>
|
||||
|
||||
#include <libsolidity/interface/OptimiserSettings.h>
|
||||
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
|
||||
@ -342,7 +344,7 @@ TestCase::TestResult YulOptimizerTest::run(ostream& _stream, string const& _line
|
||||
yul::Object obj;
|
||||
obj.code = m_ast;
|
||||
obj.analysisInfo = m_analysisInfo;
|
||||
OptimiserSuite::run(*m_dialect, &meter, obj, true);
|
||||
OptimiserSuite::run(*m_dialect, &meter, obj, true, solidity::frontend::OptimiserSettings::DefaultYulOptimiserSteps);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user