mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Introduce fine-grained optimiser settings in libevmasm
This commit is contained in:
parent
89fadd6935
commit
f9d5f7e497
@ -350,38 +350,65 @@ void Assembly::injectStart(AssemblyItem const& _i)
|
|||||||
|
|
||||||
Assembly& Assembly::optimise(bool _enable, bool _isCreation, size_t _runs)
|
Assembly& Assembly::optimise(bool _enable, bool _isCreation, size_t _runs)
|
||||||
{
|
{
|
||||||
optimiseInternal(_enable, _isCreation, _runs);
|
OptimiserSettings settings;
|
||||||
|
settings.isCreation = _isCreation;
|
||||||
|
settings.runPeephole = true;
|
||||||
|
if (_enable)
|
||||||
|
{
|
||||||
|
settings.runDeduplicate = true;
|
||||||
|
settings.runCSE = true;
|
||||||
|
settings.runConstantOptimiser = true;
|
||||||
|
}
|
||||||
|
settings.expectedExecutionsPerDeployment = _runs;
|
||||||
|
optimiseInternal(settings);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
map<u256, u256> Assembly::optimiseInternal(bool _enable, bool _isCreation, size_t _runs)
|
|
||||||
|
Assembly& Assembly::optimise(OptimiserSettings _settings)
|
||||||
{
|
{
|
||||||
|
optimiseInternal(_settings);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
map<u256, u256> Assembly::optimiseInternal(OptimiserSettings _settings)
|
||||||
|
{
|
||||||
|
// Run optimisation for sub-assemblies.
|
||||||
for (size_t subId = 0; subId < m_subs.size(); ++subId)
|
for (size_t subId = 0; subId < m_subs.size(); ++subId)
|
||||||
{
|
{
|
||||||
map<u256, u256> subTagReplacements = m_subs[subId]->optimiseInternal(_enable, false, _runs);
|
OptimiserSettings settings = _settings;
|
||||||
|
// Disable creation mode for sub-assemblies.
|
||||||
|
settings.isCreation = false;
|
||||||
|
map<u256, u256> subTagReplacements = m_subs[subId]->optimiseInternal(settings);
|
||||||
|
// Apply the replacements (can be empty).
|
||||||
BlockDeduplicator::applyTagReplacement(m_items, subTagReplacements, subId);
|
BlockDeduplicator::applyTagReplacement(m_items, subTagReplacements, subId);
|
||||||
}
|
}
|
||||||
|
|
||||||
map<u256, u256> tagReplacements;
|
map<u256, u256> tagReplacements;
|
||||||
|
// Iterate until no new optimisation possibilities are found.
|
||||||
for (unsigned count = 1; count > 0;)
|
for (unsigned count = 1; count > 0;)
|
||||||
{
|
{
|
||||||
count = 0;
|
count = 0;
|
||||||
|
|
||||||
PeepholeOptimiser peepOpt(m_items);
|
if (_settings.runPeephole)
|
||||||
while (peepOpt.optimise())
|
|
||||||
count++;
|
|
||||||
|
|
||||||
if (!_enable)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// This only modifies PushTags, we have to run again to actually remove code.
|
|
||||||
BlockDeduplicator dedup(m_items);
|
|
||||||
if (dedup.deduplicate())
|
|
||||||
{
|
{
|
||||||
tagReplacements.insert(dedup.replacedTags().begin(), dedup.replacedTags().end());
|
PeepholeOptimiser peepOpt(m_items);
|
||||||
count++;
|
while (peepOpt.optimise())
|
||||||
|
count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This only modifies PushTags, we have to run again to actually remove code.
|
||||||
|
if (_settings.runDeduplicate)
|
||||||
|
{
|
||||||
|
BlockDeduplicator dedup(m_items);
|
||||||
|
if (dedup.deduplicate())
|
||||||
|
{
|
||||||
|
tagReplacements.insert(dedup.replacedTags().begin(), dedup.replacedTags().end());
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_settings.runCSE)
|
||||||
{
|
{
|
||||||
// Control flow graph optimization has been here before but is disabled because it
|
// Control flow graph optimization has been here before but is disabled because it
|
||||||
// assumes we only jump to tags that are pushed. This is not the case anymore with
|
// assumes we only jump to tags that are pushed. This is not the case anymore with
|
||||||
@ -429,10 +456,10 @@ map<u256, u256> Assembly::optimiseInternal(bool _enable, bool _isCreation, size_
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_enable)
|
if (_settings.runConstantOptimiser)
|
||||||
ConstantOptimisationMethod::optimiseConstants(
|
ConstantOptimisationMethod::optimiseConstants(
|
||||||
_isCreation,
|
_settings.isCreation,
|
||||||
_isCreation ? 1 : _runs,
|
_settings.isCreation ? 1 : _settings.expectedExecutionsPerDeployment,
|
||||||
*this,
|
*this,
|
||||||
m_items
|
m_items
|
||||||
);
|
);
|
||||||
|
@ -97,12 +97,28 @@ public:
|
|||||||
LinkerObject const& assemble() const;
|
LinkerObject const& assemble() const;
|
||||||
bytes const& data(h256 const& _i) const { return m_data.at(_i); }
|
bytes const& data(h256 const& _i) const { return m_data.at(_i); }
|
||||||
|
|
||||||
|
struct OptimiserSettings
|
||||||
|
{
|
||||||
|
bool isCreation = false;
|
||||||
|
bool runPeephole = false;
|
||||||
|
bool runDeduplicate = false;
|
||||||
|
bool runCSE = false;
|
||||||
|
bool runConstantOptimiser = 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;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Execute optimisation passes as defined by @a _settings and return the optimised assembly.
|
||||||
|
Assembly& optimise(OptimiserSettings _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
|
||||||
/// execution gas usage is optimised. @a _isCreation should be true for the top-level assembly.
|
/// execution gas usage is optimised. @a _isCreation should be true for the top-level assembly.
|
||||||
/// @a _runs specifes an estimate on how often each opcode in this assembly will be executed,
|
/// @a _runs specifes 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.
|
/// i.e. use a small value to optimise for size and a large value to optimise for runtime.
|
||||||
/// If @a _enable is not set, will perform some simple peephole optimizations.
|
/// If @a _enable is not set, will perform some simple peephole optimizations.
|
||||||
Assembly& optimise(bool _enable, bool _isCreation = true, size_t _runs = 200);
|
Assembly& optimise(bool _enable, bool _isCreation = true, size_t _runs = 200);
|
||||||
|
|
||||||
Json::Value stream(
|
Json::Value stream(
|
||||||
std::ostream& _out,
|
std::ostream& _out,
|
||||||
std::string const& _prefix = "",
|
std::string const& _prefix = "",
|
||||||
@ -113,7 +129,7 @@ public:
|
|||||||
protected:
|
protected:
|
||||||
/// Does the same operations as @a optimise, but should only be applied to a sub and
|
/// Does the same operations as @a optimise, but should only be applied to a sub and
|
||||||
/// returns the replaced tags.
|
/// returns the replaced tags.
|
||||||
std::map<u256, u256> optimiseInternal(bool _enable, bool _isCreation, size_t _runs);
|
std::map<u256, u256> optimiseInternal(OptimiserSettings _settings);
|
||||||
|
|
||||||
unsigned bytesRequired(unsigned subTagSize) const;
|
unsigned bytesRequired(unsigned subTagSize) const;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user