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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
map<u256, u256> tagReplacements;
|
||||
// Iterate until no new optimisation possibilities are found.
|
||||
for (unsigned count = 1; count > 0;)
|
||||
{
|
||||
count = 0;
|
||||
|
||||
PeepholeOptimiser peepOpt(m_items);
|
||||
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())
|
||||
if (_settings.runPeephole)
|
||||
{
|
||||
tagReplacements.insert(dedup.replacedTags().begin(), dedup.replacedTags().end());
|
||||
count++;
|
||||
PeepholeOptimiser peepOpt(m_items);
|
||||
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
|
||||
// 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(
|
||||
_isCreation,
|
||||
_isCreation ? 1 : _runs,
|
||||
_settings.isCreation,
|
||||
_settings.isCreation ? 1 : _settings.expectedExecutionsPerDeployment,
|
||||
*this,
|
||||
m_items
|
||||
);
|
||||
|
@ -97,12 +97,28 @@ public:
|
||||
LinkerObject const& assemble() const;
|
||||
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
|
||||
/// 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,
|
||||
/// 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.
|
||||
Assembly& optimise(bool _enable, bool _isCreation = true, size_t _runs = 200);
|
||||
|
||||
Json::Value stream(
|
||||
std::ostream& _out,
|
||||
std::string const& _prefix = "",
|
||||
@ -113,7 +129,7 @@ public:
|
||||
protected:
|
||||
/// Does the same operations as @a optimise, but should only be applied to a sub and
|
||||
/// 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;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user