Optimize constant optimization.

This commit is contained in:
chriseth 2017-01-06 17:05:27 +01:00
parent f1a4976ce6
commit da5e171f3b
2 changed files with 60 additions and 39 deletions

View File

@ -38,6 +38,7 @@ unsigned ConstantOptimisationMethod::optimiseConstants(
for (AssemblyItem const& item: _items)
if (item.type() == Push)
pushes[item]++;
map<u256, AssemblyItems> pendingReplacements;
for (auto it: pushes)
{
AssemblyItem const& item = it.first;
@ -53,17 +54,22 @@ unsigned ConstantOptimisationMethod::optimiseConstants(
bigint copyGas = copy.gasNeeded();
ComputeMethod compute(params, item.data());
bigint computeGas = compute.gasNeeded();
AssemblyItems replacement;
if (copyGas < literalGas && copyGas < computeGas)
{
copy.execute(_assembly, _items);
replacement = copy.execute(_assembly);
optimisations++;
}
else if (computeGas < literalGas && computeGas < copyGas)
{
compute.execute(_assembly, _items);
replacement = compute.execute(_assembly);
optimisations++;
}
if (!replacement.empty())
pendingReplacements[item.data()] = replacement;
}
if (!pendingReplacements.empty())
replaceConstants(_items, pendingReplacements);
return optimisations;
}
@ -101,18 +107,24 @@ size_t ConstantOptimisationMethod::bytesRequired(AssemblyItems const& _items)
void ConstantOptimisationMethod::replaceConstants(
AssemblyItems& _items,
AssemblyItems const& _replacement
) const
map<u256, AssemblyItems> const& _replacements
)
{
assertThrow(_items.size() > 0, OptimizerException, "");
for (size_t i = 0; i < _items.size(); ++i)
AssemblyItems replaced;
for (AssemblyItem const& item: _items)
{
if (_items.at(i) != AssemblyItem(m_value))
continue;
_items[i] = _replacement[0];
_items.insert(_items.begin() + i + 1, _replacement.begin() + 1, _replacement.end());
i += _replacement.size() - 1;
if (item.type() == Push)
{
auto it = _replacements.find(item.data());
if (it != _replacements.end())
{
replaced += it->second;
continue;
}
}
replaced.push_back(item);
}
_items = std::move(replaced);
}
bigint LiteralMethod::gasNeeded()
@ -128,7 +140,31 @@ bigint LiteralMethod::gasNeeded()
CodeCopyMethod::CodeCopyMethod(Params const& _params, u256 const& _value):
ConstantOptimisationMethod(_params, _value)
{
m_copyRoutine = AssemblyItems{
}
bigint CodeCopyMethod::gasNeeded()
{
return combineGas(
// Run gas: we ignore memory increase costs
simpleRunGas(copyRoutine()) + GasCosts::copyGas,
// Data gas for copy routines: Some bytes are zero, but we ignore them.
bytesRequired(copyRoutine()) * (m_params.isCreation ? GasCosts::txDataNonZeroGas : GasCosts::createDataGas),
// Data gas for data itself
dataGas(toBigEndian(m_value))
);
}
AssemblyItems CodeCopyMethod::execute(Assembly& _assembly)
{
bytes data = toBigEndian(m_value);
AssemblyItems actualCopyRoutine = copyRoutine();
actualCopyRoutine[4] = _assembly.newData(data);
return actualCopyRoutine;
}
AssemblyItems const& CodeCopyMethod::copyRoutine() const
{
AssemblyItems static copyRoutine{
u256(0),
Instruction::DUP1,
Instruction::MLOAD, // back up memory
@ -141,25 +177,7 @@ CodeCopyMethod::CodeCopyMethod(Params const& _params, u256 const& _value):
Instruction::SWAP2,
Instruction::MSTORE
};
}
bigint CodeCopyMethod::gasNeeded()
{
return combineGas(
// Run gas: we ignore memory increase costs
simpleRunGas(m_copyRoutine) + GasCosts::copyGas,
// Data gas for copy routines: Some bytes are zero, but we ignore them.
bytesRequired(m_copyRoutine) * (m_params.isCreation ? GasCosts::txDataNonZeroGas : GasCosts::createDataGas),
// Data gas for data itself
dataGas(toBigEndian(m_value))
);
}
void CodeCopyMethod::execute(Assembly& _assembly, AssemblyItems& _items)
{
bytes data = toBigEndian(m_value);
m_copyRoutine[4] = _assembly.newData(data);
replaceConstants(_items, m_copyRoutine);
return copyRoutine;
}
AssemblyItems ComputeMethod::findRepresentation(u256 const& _value)

View File

@ -60,7 +60,10 @@ public:
explicit ConstantOptimisationMethod(Params const& _params, u256 const& _value):
m_params(_params), m_value(_value) {}
virtual bigint gasNeeded() = 0;
virtual void execute(Assembly& _assembly, AssemblyItems& _items) = 0;
/// Executes the method, potentially appending to the assembly and returns a vector of
/// assembly items the constant should be relpaced with in one sweep.
/// If the vector is empty, the constants will not be deleted.
virtual AssemblyItems execute(Assembly& _assembly) = 0;
protected:
size_t dataSize() const { return std::max<size_t>(1, dev::bytesRequired(m_value)); }
@ -83,8 +86,8 @@ protected:
return m_params.runs * _runGas + m_params.multiplicity * _repeatedDataGas + _uniqueDataGas;
}
/// Replaces the constant by the code given in @a _replacement.
void replaceConstants(AssemblyItems& _items, AssemblyItems const& _replacement) const;
/// Replaces all constants i by the code given in @a _replacement[i].
static void replaceConstants(AssemblyItems& _items, std::map<u256, AssemblyItems> const& _replacement);
Params m_params;
u256 const& m_value;
@ -100,7 +103,7 @@ public:
explicit LiteralMethod(Params const& _params, u256 const& _value):
ConstantOptimisationMethod(_params, _value) {}
virtual bigint gasNeeded() override;
virtual void execute(Assembly&, AssemblyItems&) override {}
virtual AssemblyItems execute(Assembly&) override { return AssemblyItems{}; }
};
/**
@ -111,10 +114,10 @@ class CodeCopyMethod: public ConstantOptimisationMethod
public:
explicit CodeCopyMethod(Params const& _params, u256 const& _value);
virtual bigint gasNeeded() override;
virtual void execute(Assembly& _assembly, AssemblyItems& _items) override;
virtual AssemblyItems execute(Assembly& _assembly) override;
protected:
AssemblyItems m_copyRoutine;
AssemblyItems const& copyRoutine() const;
};
/**
@ -130,9 +133,9 @@ public:
}
virtual bigint gasNeeded() override { return gasNeeded(m_routine); }
virtual void execute(Assembly&, AssemblyItems& _items) override
virtual AssemblyItems execute(Assembly&) override
{
replaceConstants(_items, m_routine);
return m_routine;
}
protected: