mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Introduce global optimiser settings.
This commit is contained in:
parent
0e475438a9
commit
cf5c13f9c7
@ -66,10 +66,23 @@ explanatory purposes.
|
|||||||
{
|
{
|
||||||
// Required for Solidity: Sorted list of remappings
|
// Required for Solidity: Sorted list of remappings
|
||||||
remappings: [ ":g/dir" ],
|
remappings: [ ":g/dir" ],
|
||||||
// Optional: Optimizer settings (enabled defaults to false)
|
// Optional: Optimizer settings. The fields "enabled" and "runs" are deprecated
|
||||||
|
// and are only given for backwards-compatibility.
|
||||||
optimizer: {
|
optimizer: {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
runs: 500
|
runs: 500,
|
||||||
|
details: {
|
||||||
|
// peephole defaults to "true"
|
||||||
|
peephole: true,
|
||||||
|
// jumpdestRemover defaults to "true"
|
||||||
|
jumpdestRemover: true,
|
||||||
|
orderLiterals: false,
|
||||||
|
deduplicate: false,
|
||||||
|
cse: false,
|
||||||
|
constantOptimizer: false,
|
||||||
|
yul: false,
|
||||||
|
yulDetails: {}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
// Required for Solidity: File and name of the contract or library this
|
// Required for Solidity: File and name of the contract or library this
|
||||||
// metadata is created for.
|
// metadata is created for.
|
||||||
|
@ -113,7 +113,8 @@ public:
|
|||||||
size_t expectedExecutionsPerDeployment = 200;
|
size_t expectedExecutionsPerDeployment = 200;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Execute optimisation passes as defined by @a _settings and return the optimised assembly.
|
/// Modify and return the current assembly such that creation and execution gas usage
|
||||||
|
/// is optimised according to the settings in @a _settings.
|
||||||
Assembly& optimise(OptimiserSettings const& _settings);
|
Assembly& optimise(OptimiserSettings const& _settings);
|
||||||
|
|
||||||
/// Modify (if @a _enable is set) and return the current assembly such that creation and
|
/// Modify (if @a _enable is set) and return the current assembly such that creation and
|
||||||
|
@ -86,6 +86,7 @@ set(sources
|
|||||||
interface/GasEstimator.h
|
interface/GasEstimator.h
|
||||||
interface/Natspec.cpp
|
interface/Natspec.cpp
|
||||||
interface/Natspec.h
|
interface/Natspec.h
|
||||||
|
interface/OptimiserSettings.h
|
||||||
interface/ReadFile.h
|
interface/ReadFile.h
|
||||||
interface/StandardCompiler.cpp
|
interface/StandardCompiler.cpp
|
||||||
interface/StandardCompiler.h
|
interface/StandardCompiler.h
|
||||||
|
@ -35,16 +35,21 @@ void Compiler::compileContract(
|
|||||||
bytes const& _metadata
|
bytes const& _metadata
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
ContractCompiler runtimeCompiler(nullptr, m_runtimeContext, m_optimize, m_optimizeRuns);
|
ContractCompiler runtimeCompiler(
|
||||||
|
nullptr,
|
||||||
|
m_runtimeContext,
|
||||||
|
m_optimiserSettings.runOrderLiterals,
|
||||||
|
m_optimiserSettings.expectedExecutionsPerDeployment
|
||||||
|
);
|
||||||
runtimeCompiler.compileContract(_contract, _otherCompilers);
|
runtimeCompiler.compileContract(_contract, _otherCompilers);
|
||||||
m_runtimeContext.appendAuxiliaryData(_metadata);
|
m_runtimeContext.appendAuxiliaryData(_metadata);
|
||||||
|
|
||||||
// This might modify m_runtimeContext because it can access runtime functions at
|
// This might modify m_runtimeContext because it can access runtime functions at
|
||||||
// creation time.
|
// creation time.
|
||||||
ContractCompiler creationCompiler(&runtimeCompiler, m_context, m_optimize, 1);
|
ContractCompiler creationCompiler(&runtimeCompiler, m_context, m_optimiserSettings.runOrderLiterals, 1);
|
||||||
m_runtimeSub = creationCompiler.compileConstructor(_contract, _otherCompilers);
|
m_runtimeSub = creationCompiler.compileConstructor(_contract, _otherCompilers);
|
||||||
|
|
||||||
m_context.optimise(m_optimize, m_optimizeRuns);
|
m_context.optimise(m_optimiserSettings);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<eth::Assembly> Compiler::runtimeAssemblyPtr() const
|
std::shared_ptr<eth::Assembly> Compiler::runtimeAssemblyPtr() const
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <libsolidity/codegen/CompilerContext.h>
|
#include <libsolidity/codegen/CompilerContext.h>
|
||||||
|
#include <libsolidity/interface/OptimiserSettings.h>
|
||||||
#include <liblangutil/EVMVersion.h>
|
#include <liblangutil/EVMVersion.h>
|
||||||
#include <libevmasm/Assembly.h>
|
#include <libevmasm/Assembly.h>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
@ -34,9 +35,8 @@ namespace solidity {
|
|||||||
class Compiler
|
class Compiler
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit Compiler(langutil::EVMVersion _evmVersion = langutil::EVMVersion{}, bool _optimize = false, unsigned _runs = 200):
|
explicit Compiler(langutil::EVMVersion _evmVersion, OptimiserSettings _optimiserSettings):
|
||||||
m_optimize(_optimize),
|
m_optimiserSettings(std::move(_optimiserSettings)),
|
||||||
m_optimizeRuns(_runs),
|
|
||||||
m_runtimeContext(_evmVersion),
|
m_runtimeContext(_evmVersion),
|
||||||
m_context(_evmVersion, &m_runtimeContext)
|
m_context(_evmVersion, &m_runtimeContext)
|
||||||
{ }
|
{ }
|
||||||
@ -78,8 +78,7 @@ public:
|
|||||||
eth::AssemblyItem functionEntryLabel(FunctionDefinition const& _function) const;
|
eth::AssemblyItem functionEntryLabel(FunctionDefinition const& _function) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool const m_optimize;
|
OptimiserSettings const m_optimiserSettings;
|
||||||
unsigned const m_optimizeRuns;
|
|
||||||
CompilerContext m_runtimeContext;
|
CompilerContext m_runtimeContext;
|
||||||
size_t m_runtimeSub = size_t(-1); ///< Identifier of the runtime sub-assembly, if present.
|
size_t m_runtimeSub = size_t(-1); ///< Identifier of the runtime sub-assembly, if present.
|
||||||
CompilerContext m_context;
|
CompilerContext m_context;
|
||||||
|
@ -447,6 +447,21 @@ void CompilerContext::updateSourceLocation()
|
|||||||
m_asm->setSourceLocation(m_visitedNodes.empty() ? SourceLocation() : m_visitedNodes.top()->location());
|
m_asm->setSourceLocation(m_visitedNodes.empty() ? SourceLocation() : m_visitedNodes.top()->location());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
eth::Assembly::OptimiserSettings CompilerContext::translateOptimiserSettings(OptimiserSettings const& _settings)
|
||||||
|
{
|
||||||
|
// Constructing it this way so that we notice changes in the fields.
|
||||||
|
eth::Assembly::OptimiserSettings asmSettings{false, false, false, false, false, false, m_evmVersion, 0};
|
||||||
|
asmSettings.isCreation = true;
|
||||||
|
asmSettings.runJumpdestRemover = _settings.runJumpdestRemover;
|
||||||
|
asmSettings.runPeephole = _settings.runPeephole;
|
||||||
|
asmSettings.runDeduplicate = _settings.runDeduplicate;
|
||||||
|
asmSettings.runCSE = _settings.runCSE;
|
||||||
|
asmSettings.runConstantOptimiser = _settings.runConstantOptimiser;
|
||||||
|
asmSettings.expectedExecutionsPerDeployment = _settings.expectedExecutionsPerDeployment;
|
||||||
|
asmSettings.evmVersion = m_evmVersion;
|
||||||
|
return asmSettings;
|
||||||
|
}
|
||||||
|
|
||||||
eth::AssemblyItem CompilerContext::FunctionCompilationQueue::entryLabel(
|
eth::AssemblyItem CompilerContext::FunctionCompilationQueue::entryLabel(
|
||||||
Declaration const& _declaration,
|
Declaration const& _declaration,
|
||||||
CompilerContext& _context
|
CompilerContext& _context
|
||||||
|
@ -27,6 +27,8 @@
|
|||||||
#include <libsolidity/ast/Types.h>
|
#include <libsolidity/ast/Types.h>
|
||||||
#include <libsolidity/codegen/ABIFunctions.h>
|
#include <libsolidity/codegen/ABIFunctions.h>
|
||||||
|
|
||||||
|
#include <libsolidity/interface/OptimiserSettings.h>
|
||||||
|
|
||||||
#include <libevmasm/Assembly.h>
|
#include <libevmasm/Assembly.h>
|
||||||
#include <libevmasm/Instruction.h>
|
#include <libevmasm/Instruction.h>
|
||||||
#include <liblangutil/EVMVersion.h>
|
#include <liblangutil/EVMVersion.h>
|
||||||
@ -221,7 +223,7 @@ public:
|
|||||||
void appendAuxiliaryData(bytes const& _data) { m_asm->appendAuxiliaryDataToEnd(_data); }
|
void appendAuxiliaryData(bytes const& _data) { m_asm->appendAuxiliaryDataToEnd(_data); }
|
||||||
|
|
||||||
/// Run optimisation step.
|
/// Run optimisation step.
|
||||||
void optimise(bool _fullOptimsation, unsigned _runs = 200) { m_asm->optimise(_fullOptimsation, m_evmVersion, true, _runs); }
|
void optimise(OptimiserSettings const& _settings) { m_asm->optimise(translateOptimiserSettings(_settings)); }
|
||||||
|
|
||||||
/// @returns the runtime context if in creation mode and runtime context is set, nullptr otherwise.
|
/// @returns the runtime context if in creation mode and runtime context is set, nullptr otherwise.
|
||||||
CompilerContext* runtimeContext() const { return m_runtimeContext; }
|
CompilerContext* runtimeContext() const { return m_runtimeContext; }
|
||||||
@ -271,6 +273,8 @@ private:
|
|||||||
/// Updates source location set in the assembly.
|
/// Updates source location set in the assembly.
|
||||||
void updateSourceLocation();
|
void updateSourceLocation();
|
||||||
|
|
||||||
|
eth::Assembly::OptimiserSettings translateOptimiserSettings(OptimiserSettings const& _settings);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper class that manages function labels and ensures that referenced functions are
|
* Helper class that manages function labels and ensures that referenced functions are
|
||||||
* compiled in a specific order.
|
* compiled in a specific order.
|
||||||
|
@ -391,7 +391,7 @@ void ContractCompiler::appendFunctionSelector(ContractDefinition const& _contrac
|
|||||||
sortedIDs.emplace_back(it.first);
|
sortedIDs.emplace_back(it.first);
|
||||||
}
|
}
|
||||||
std::sort(sortedIDs.begin(), sortedIDs.end());
|
std::sort(sortedIDs.begin(), sortedIDs.end());
|
||||||
appendInternalSelector(callDataUnpackerEntryPoints, sortedIDs, notFound, m_optimise_runs);
|
appendInternalSelector(callDataUnpackerEntryPoints, sortedIDs, notFound, m_optimiseRuns);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_context << notFound;
|
m_context << notFound;
|
||||||
@ -484,7 +484,7 @@ void ContractCompiler::initializeStateVariables(ContractDefinition const& _contr
|
|||||||
solAssert(!_contract.isLibrary(), "Tried to initialize state variables of library.");
|
solAssert(!_contract.isLibrary(), "Tried to initialize state variables of library.");
|
||||||
for (VariableDeclaration const* variable: _contract.stateVariables())
|
for (VariableDeclaration const* variable: _contract.stateVariables())
|
||||||
if (variable->value() && !variable->isConstant())
|
if (variable->value() && !variable->isConstant())
|
||||||
ExpressionCompiler(m_context, m_optimise).appendStateVariableInitialization(*variable);
|
ExpressionCompiler(m_context, m_optimiseOrderLiterals).appendStateVariableInitialization(*variable);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ContractCompiler::visit(VariableDeclaration const& _variableDeclaration)
|
bool ContractCompiler::visit(VariableDeclaration const& _variableDeclaration)
|
||||||
@ -497,9 +497,9 @@ bool ContractCompiler::visit(VariableDeclaration const& _variableDeclaration)
|
|||||||
m_continueTags.clear();
|
m_continueTags.clear();
|
||||||
|
|
||||||
if (_variableDeclaration.isConstant())
|
if (_variableDeclaration.isConstant())
|
||||||
ExpressionCompiler(m_context, m_optimise).appendConstStateVariableAccessor(_variableDeclaration);
|
ExpressionCompiler(m_context, m_optimiseOrderLiterals).appendConstStateVariableAccessor(_variableDeclaration);
|
||||||
else
|
else
|
||||||
ExpressionCompiler(m_context, m_optimise).appendStateVariableAccessor(_variableDeclaration);
|
ExpressionCompiler(m_context, m_optimiseOrderLiterals).appendStateVariableAccessor(_variableDeclaration);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -1053,7 +1053,7 @@ void ContractCompiler::appendStackVariableInitialisation(VariableDeclaration con
|
|||||||
|
|
||||||
void ContractCompiler::compileExpression(Expression const& _expression, TypePointer const& _targetType)
|
void ContractCompiler::compileExpression(Expression const& _expression, TypePointer const& _targetType)
|
||||||
{
|
{
|
||||||
ExpressionCompiler expressionCompiler(m_context, m_optimise);
|
ExpressionCompiler expressionCompiler(m_context, m_optimiseOrderLiterals);
|
||||||
expressionCompiler.compile(_expression);
|
expressionCompiler.compile(_expression);
|
||||||
if (_targetType)
|
if (_targetType)
|
||||||
CompilerUtils(m_context).convertType(*_expression.annotation().type, *_targetType);
|
CompilerUtils(m_context).convertType(*_expression.annotation().type, *_targetType);
|
||||||
|
@ -38,9 +38,9 @@ namespace solidity {
|
|||||||
class ContractCompiler: private ASTConstVisitor
|
class ContractCompiler: private ASTConstVisitor
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit ContractCompiler(ContractCompiler* _runtimeCompiler, CompilerContext& _context, bool _optimise, size_t _optimise_runs = 200):
|
explicit ContractCompiler(ContractCompiler* _runtimeCompiler, CompilerContext& _context, bool _optimiseOrderLiterals, size_t _optimiseRuns):
|
||||||
m_optimise(_optimise),
|
m_optimiseOrderLiterals(_optimiseOrderLiterals),
|
||||||
m_optimise_runs(_optimise_runs),
|
m_optimiseRuns(_optimiseRuns),
|
||||||
m_runtimeCompiler(_runtimeCompiler),
|
m_runtimeCompiler(_runtimeCompiler),
|
||||||
m_context(_context)
|
m_context(_context)
|
||||||
{
|
{
|
||||||
@ -130,8 +130,8 @@ private:
|
|||||||
/// Sets the stack height for the visited loop.
|
/// Sets the stack height for the visited loop.
|
||||||
void storeStackHeight(ASTNode const* _node);
|
void storeStackHeight(ASTNode const* _node);
|
||||||
|
|
||||||
bool const m_optimise;
|
bool const m_optimiseOrderLiterals;
|
||||||
size_t const m_optimise_runs = 200;
|
size_t const m_optimiseRuns = 200;
|
||||||
/// Pointer to the runtime compiler in case this is a creation compiler.
|
/// Pointer to the runtime compiler in case this is a creation compiler.
|
||||||
ContractCompiler* m_runtimeCompiler = nullptr;
|
ContractCompiler* m_runtimeCompiler = nullptr;
|
||||||
CompilerContext& m_context;
|
CompilerContext& m_context;
|
||||||
|
@ -449,7 +449,7 @@ bool ExpressionCompiler::visit(BinaryOperation const& _binaryOperation)
|
|||||||
{
|
{
|
||||||
return dynamic_cast<Literal const*>(&_e) || _e.annotation().type->category() == Type::Category::RationalNumber;
|
return dynamic_cast<Literal const*>(&_e) || _e.annotation().type->category() == Type::Category::RationalNumber;
|
||||||
};
|
};
|
||||||
bool swap = m_optimize && TokenTraits::isCommutativeOp(c_op) && isLiteral(rightExpression) && !isLiteral(leftExpression);
|
bool swap = m_optimiseOrderLiterals && TokenTraits::isCommutativeOp(c_op) && isLiteral(rightExpression) && !isLiteral(leftExpression);
|
||||||
if (swap)
|
if (swap)
|
||||||
{
|
{
|
||||||
leftExpression.accept(*this);
|
leftExpression.accept(*this);
|
||||||
|
@ -55,11 +55,8 @@ class ArrayType;
|
|||||||
class ExpressionCompiler: private ASTConstVisitor
|
class ExpressionCompiler: private ASTConstVisitor
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
/// Appends code for a State Variable accessor function
|
explicit ExpressionCompiler(CompilerContext& _compilerContext, bool _optimiseOrderLiterals = false):
|
||||||
static void appendStateVariableAccessor(CompilerContext& _context, VariableDeclaration const& _varDecl, bool _optimize = false);
|
m_optimiseOrderLiterals(_optimiseOrderLiterals), m_context(_compilerContext) {}
|
||||||
|
|
||||||
explicit ExpressionCompiler(CompilerContext& _compilerContext, bool _optimize = false):
|
|
||||||
m_optimize(_optimize), m_context(_compilerContext) {}
|
|
||||||
|
|
||||||
/// Compile the given @a _expression and leave its value on the stack.
|
/// Compile the given @a _expression and leave its value on the stack.
|
||||||
void compile(Expression const& _expression);
|
void compile(Expression const& _expression);
|
||||||
@ -127,7 +124,7 @@ private:
|
|||||||
/// @returns the CompilerUtils object containing the current context.
|
/// @returns the CompilerUtils object containing the current context.
|
||||||
CompilerUtils utils();
|
CompilerUtils utils();
|
||||||
|
|
||||||
bool m_optimize;
|
bool m_optimiseOrderLiterals;
|
||||||
CompilerContext& m_context;
|
CompilerContext& m_context;
|
||||||
std::unique_ptr<LValue> m_currentLValue;
|
std::unique_ptr<LValue> m_currentLValue;
|
||||||
|
|
||||||
|
@ -108,11 +108,17 @@ void CompilerStack::setLibraries(std::map<std::string, h160> const& _libraries)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void CompilerStack::setOptimiserSettings(bool _optimize, unsigned _runs)
|
void CompilerStack::setOptimiserSettings(bool _optimize, unsigned _runs)
|
||||||
|
{
|
||||||
|
OptimiserSettings settings = _optimize ? OptimiserSettings::enabled() : OptimiserSettings::minimal();
|
||||||
|
settings.expectedExecutionsPerDeployment = _runs;
|
||||||
|
setOptimiserSettings(std::move(settings));
|
||||||
|
}
|
||||||
|
|
||||||
|
void CompilerStack::setOptimiserSettings(OptimiserSettings _settings)
|
||||||
{
|
{
|
||||||
if (m_stackState >= ParsingSuccessful)
|
if (m_stackState >= ParsingSuccessful)
|
||||||
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Must set optimiser settings before parsing."));
|
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Must set optimiser settings before parsing."));
|
||||||
m_optimize = _optimize;
|
m_optimiserSettings = std::move(_settings);
|
||||||
m_optimizeRuns = _runs;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CompilerStack::useMetadataLiteralSources(bool _metadataLiteralSources)
|
void CompilerStack::useMetadataLiteralSources(bool _metadataLiteralSources)
|
||||||
@ -146,8 +152,7 @@ void CompilerStack::reset(bool _keepSources)
|
|||||||
m_unhandledSMTLib2Queries.clear();
|
m_unhandledSMTLib2Queries.clear();
|
||||||
m_libraries.clear();
|
m_libraries.clear();
|
||||||
m_evmVersion = langutil::EVMVersion();
|
m_evmVersion = langutil::EVMVersion();
|
||||||
m_optimize = false;
|
m_optimiserSettings = OptimiserSettings::minimal();
|
||||||
m_optimizeRuns = 200;
|
|
||||||
m_globalContext.reset();
|
m_globalContext.reset();
|
||||||
m_scopes.clear();
|
m_scopes.clear();
|
||||||
m_sourceOrder.clear();
|
m_sourceOrder.clear();
|
||||||
@ -840,7 +845,7 @@ void CompilerStack::compileContract(
|
|||||||
|
|
||||||
Contract& compiledContract = m_contracts.at(_contract.fullyQualifiedName());
|
Contract& compiledContract = m_contracts.at(_contract.fullyQualifiedName());
|
||||||
|
|
||||||
shared_ptr<Compiler> compiler = make_shared<Compiler>(m_evmVersion, m_optimize, m_optimizeRuns);
|
shared_ptr<Compiler> compiler = make_shared<Compiler>(m_evmVersion, m_optimiserSettings);
|
||||||
compiledContract.compiler = compiler;
|
compiledContract.compiler = compiler;
|
||||||
|
|
||||||
string metadata = createMetadata(compiledContract);
|
string metadata = createMetadata(compiledContract);
|
||||||
@ -953,8 +958,35 @@ string CompilerStack::createMetadata(Contract const& _contract) const
|
|||||||
meta["sources"][s.first]["urls"].append("bzzr://" + toHex(s.second.swarmHash().asBytes()));
|
meta["sources"][s.first]["urls"].append("bzzr://" + toHex(s.second.swarmHash().asBytes()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
meta["settings"]["optimizer"]["enabled"] = m_optimize;
|
|
||||||
meta["settings"]["optimizer"]["runs"] = m_optimizeRuns;
|
static_assert(sizeof(m_optimiserSettings.expectedExecutionsPerDeployment) <= sizeof(Json::LargestUInt), "Invalid word size.");
|
||||||
|
solAssert(static_cast<Json::LargestUInt>(m_optimiserSettings.expectedExecutionsPerDeployment) < std::numeric_limits<Json::LargestUInt>::max(), "");
|
||||||
|
meta["settings"]["optimizer"]["runs"] = Json::Value(Json::LargestUInt(m_optimiserSettings.expectedExecutionsPerDeployment));
|
||||||
|
|
||||||
|
/// Backwards compatibility: If set to one of the default settings, do not provide details.
|
||||||
|
OptimiserSettings settingsWithoutRuns = m_optimiserSettings;
|
||||||
|
// reset to default
|
||||||
|
settingsWithoutRuns.expectedExecutionsPerDeployment = OptimiserSettings::minimal().expectedExecutionsPerDeployment;
|
||||||
|
if (settingsWithoutRuns == OptimiserSettings::minimal())
|
||||||
|
meta["settings"]["optimizer"]["enabled"] = false;
|
||||||
|
else if (settingsWithoutRuns == OptimiserSettings::enabled())
|
||||||
|
meta["settings"]["optimizer"]["enabled"] = true;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Json::Value details{Json::objectValue};
|
||||||
|
|
||||||
|
details["orderLiterals"] = m_optimiserSettings.runOrderLiterals;
|
||||||
|
details["jumpdestRemover"] = m_optimiserSettings.runJumpdestRemover;
|
||||||
|
details["peephole"] = m_optimiserSettings.runPeephole;
|
||||||
|
details["deduplicate"] = m_optimiserSettings.runDeduplicate;
|
||||||
|
details["cse"] = m_optimiserSettings.runCSE;
|
||||||
|
details["constantOptimizer"] = m_optimiserSettings.runConstantOptimiser;
|
||||||
|
details["yul"] = m_optimiserSettings.runYulOptimiser;
|
||||||
|
details["yulDetails"] = Json::objectValue;
|
||||||
|
|
||||||
|
meta["settings"]["optimizer"]["details"] = std::move(details);
|
||||||
|
}
|
||||||
|
|
||||||
meta["settings"]["evmVersion"] = m_evmVersion.name();
|
meta["settings"]["evmVersion"] = m_evmVersion.name();
|
||||||
meta["settings"]["compilationTarget"][_contract.contract->sourceUnitName()] =
|
meta["settings"]["compilationTarget"][_contract.contract->sourceUnitName()] =
|
||||||
_contract.contract->annotation().canonicalName;
|
_contract.contract->annotation().canonicalName;
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <libsolidity/interface/ReadFile.h>
|
#include <libsolidity/interface/ReadFile.h>
|
||||||
|
#include <libsolidity/interface/OptimiserSettings.h>
|
||||||
|
|
||||||
#include <liblangutil/ErrorReporter.h>
|
#include <liblangutil/ErrorReporter.h>
|
||||||
#include <liblangutil/EVMVersion.h>
|
#include <liblangutil/EVMVersion.h>
|
||||||
@ -128,6 +129,10 @@ public:
|
|||||||
/// Must be set before parsing.
|
/// Must be set before parsing.
|
||||||
void setOptimiserSettings(bool _optimize, unsigned _runs = 200);
|
void setOptimiserSettings(bool _optimize, unsigned _runs = 200);
|
||||||
|
|
||||||
|
/// Changes the optimiser settings.
|
||||||
|
/// Must be set before parsing.
|
||||||
|
void setOptimiserSettings(OptimiserSettings _settings);
|
||||||
|
|
||||||
/// Set the EVM version used before running compile.
|
/// Set the EVM version used before running compile.
|
||||||
/// When called without an argument it will revert to the default version.
|
/// When called without an argument it will revert to the default version.
|
||||||
/// Must be set before parsing.
|
/// Must be set before parsing.
|
||||||
@ -342,8 +347,7 @@ private:
|
|||||||
) const;
|
) const;
|
||||||
|
|
||||||
ReadCallback::Callback m_readFile;
|
ReadCallback::Callback m_readFile;
|
||||||
bool m_optimize = false;
|
OptimiserSettings m_optimiserSettings;
|
||||||
unsigned m_optimizeRuns = 200;
|
|
||||||
langutil::EVMVersion m_evmVersion;
|
langutil::EVMVersion m_evmVersion;
|
||||||
std::set<std::string> m_requestedContractNames;
|
std::set<std::string> m_requestedContractNames;
|
||||||
std::map<std::string, h160> m_libraries;
|
std::map<std::string, h160> m_libraries;
|
||||||
|
105
libsolidity/interface/OptimiserSettings.h
Normal file
105
libsolidity/interface/OptimiserSettings.h
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
/*
|
||||||
|
This file is part of solidity.
|
||||||
|
|
||||||
|
solidity is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
solidity is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with solidity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* @author Alex Beregszaszi
|
||||||
|
* @date 2017
|
||||||
|
* Helper class for optimiser settings.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
|
||||||
|
namespace dev
|
||||||
|
{
|
||||||
|
namespace solidity
|
||||||
|
{
|
||||||
|
|
||||||
|
struct OptimiserSettings
|
||||||
|
{
|
||||||
|
/// No optimisations at all - not recommended.
|
||||||
|
static OptimiserSettings none()
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
/// Minimal optimisations: Peephole and jumpdest remover
|
||||||
|
static OptimiserSettings minimal()
|
||||||
|
{
|
||||||
|
OptimiserSettings s = none();
|
||||||
|
s.runJumpdestRemover = true;
|
||||||
|
s.runPeephole = true;
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
/// Standard optimisations.
|
||||||
|
static OptimiserSettings enabled()
|
||||||
|
{
|
||||||
|
OptimiserSettings s;
|
||||||
|
s.runOrderLiterals = true;
|
||||||
|
s.runJumpdestRemover = true;
|
||||||
|
s.runPeephole = true;
|
||||||
|
s.runDeduplicate = true;
|
||||||
|
s.runCSE = true;
|
||||||
|
s.runConstantOptimiser = true;
|
||||||
|
// The only disabled one
|
||||||
|
s.runYulOptimiser = false;
|
||||||
|
s.expectedExecutionsPerDeployment = 200;
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
/// Standard optimisations plus yul optimiser.
|
||||||
|
static OptimiserSettings full()
|
||||||
|
{
|
||||||
|
OptimiserSettings s = enabled();
|
||||||
|
s.runYulOptimiser = true;
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(OptimiserSettings const& _other) const
|
||||||
|
{
|
||||||
|
return
|
||||||
|
runOrderLiterals == _other.runOrderLiterals &&
|
||||||
|
runJumpdestRemover == _other.runJumpdestRemover &&
|
||||||
|
runPeephole == _other.runPeephole &&
|
||||||
|
runDeduplicate == _other.runDeduplicate &&
|
||||||
|
runCSE == _other.runCSE &&
|
||||||
|
runConstantOptimiser == _other.runConstantOptimiser &&
|
||||||
|
runYulOptimiser == _other.runYulOptimiser &&
|
||||||
|
expectedExecutionsPerDeployment == _other.expectedExecutionsPerDeployment;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Move literals to the right of commutative binary operators during code generation.
|
||||||
|
/// This helps exploiting associativity.
|
||||||
|
bool runOrderLiterals = false;
|
||||||
|
/// Non-referenced jump destination remover.
|
||||||
|
bool runJumpdestRemover = false;
|
||||||
|
/// Peephole optimizer
|
||||||
|
bool runPeephole = false;
|
||||||
|
/// Assembly block deduplicator
|
||||||
|
bool runDeduplicate = false;
|
||||||
|
/// Common subexpression eliminator based on assembly items.
|
||||||
|
bool runCSE = false;
|
||||||
|
/// Constant optimizer, which tries to find better representations that satisfy the given
|
||||||
|
/// size/cost-trade-off.
|
||||||
|
bool runConstantOptimiser = false;
|
||||||
|
/// Yul optimiser with default settings. Will only run on certain parts of the code for now.
|
||||||
|
bool runYulOptimiser = false;
|
||||||
|
/// 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;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -84,7 +84,10 @@ eth::AssemblyItems compileContract(std::shared_ptr<CharStream> _sourceCode)
|
|||||||
for (ASTPointer<ASTNode> const& node: sourceUnit->nodes())
|
for (ASTPointer<ASTNode> const& node: sourceUnit->nodes())
|
||||||
if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
|
if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
|
||||||
{
|
{
|
||||||
Compiler compiler(dev::test::Options::get().evmVersion());
|
Compiler compiler(
|
||||||
|
dev::test::Options::get().evmVersion(),
|
||||||
|
dev::test::Options::get().optimize ? OptimiserSettings::enabled() : OptimiserSettings::minimal()
|
||||||
|
);
|
||||||
compiler.compileContract(*contract, map<ContractDefinition const*, shared_ptr<Compiler const>>{}, bytes());
|
compiler.compileContract(*contract, map<ContractDefinition const*, shared_ptr<Compiler const>>{}, bytes());
|
||||||
|
|
||||||
return compiler.runtimeAssemblyItems();
|
return compiler.runtimeAssemblyItems();
|
||||||
|
Loading…
Reference in New Issue
Block a user