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) for (AssemblyItem const& item: _items)
if (item.type() == Push) if (item.type() == Push)
pushes[item]++; pushes[item]++;
map<u256, AssemblyItems> pendingReplacements;
for (auto it: pushes) for (auto it: pushes)
{ {
AssemblyItem const& item = it.first; AssemblyItem const& item = it.first;
@ -53,17 +54,22 @@ unsigned ConstantOptimisationMethod::optimiseConstants(
bigint copyGas = copy.gasNeeded(); bigint copyGas = copy.gasNeeded();
ComputeMethod compute(params, item.data()); ComputeMethod compute(params, item.data());
bigint computeGas = compute.gasNeeded(); bigint computeGas = compute.gasNeeded();
AssemblyItems replacement;
if (copyGas < literalGas && copyGas < computeGas) if (copyGas < literalGas && copyGas < computeGas)
{ {
copy.execute(_assembly, _items); replacement = copy.execute(_assembly);
optimisations++; optimisations++;
} }
else if (computeGas < literalGas && computeGas < copyGas) else if (computeGas < literalGas && computeGas < copyGas)
{ {
compute.execute(_assembly, _items); replacement = compute.execute(_assembly);
optimisations++; optimisations++;
} }
if (!replacement.empty())
pendingReplacements[item.data()] = replacement;
} }
if (!pendingReplacements.empty())
replaceConstants(_items, pendingReplacements);
return optimisations; return optimisations;
} }
@ -101,19 +107,25 @@ size_t ConstantOptimisationMethod::bytesRequired(AssemblyItems const& _items)
void ConstantOptimisationMethod::replaceConstants( void ConstantOptimisationMethod::replaceConstants(
AssemblyItems& _items, AssemblyItems& _items,
AssemblyItems const& _replacement map<u256, AssemblyItems> const& _replacements
) const )
{ {
assertThrow(_items.size() > 0, OptimizerException, ""); AssemblyItems replaced;
for (size_t i = 0; i < _items.size(); ++i) for (AssemblyItem const& item: _items)
{ {
if (_items.at(i) != AssemblyItem(m_value)) if (item.type() == Push)
{
auto it = _replacements.find(item.data());
if (it != _replacements.end())
{
replaced += it->second;
continue; continue;
_items[i] = _replacement[0];
_items.insert(_items.begin() + i + 1, _replacement.begin() + 1, _replacement.end());
i += _replacement.size() - 1;
} }
} }
replaced.push_back(item);
}
_items = std::move(replaced);
}
bigint LiteralMethod::gasNeeded() bigint LiteralMethod::gasNeeded()
{ {
@ -128,7 +140,31 @@ bigint LiteralMethod::gasNeeded()
CodeCopyMethod::CodeCopyMethod(Params const& _params, u256 const& _value): CodeCopyMethod::CodeCopyMethod(Params const& _params, u256 const& _value):
ConstantOptimisationMethod(_params, _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), u256(0),
Instruction::DUP1, Instruction::DUP1,
Instruction::MLOAD, // back up memory Instruction::MLOAD, // back up memory
@ -141,25 +177,7 @@ CodeCopyMethod::CodeCopyMethod(Params const& _params, u256 const& _value):
Instruction::SWAP2, Instruction::SWAP2,
Instruction::MSTORE Instruction::MSTORE
}; };
} return copyRoutine;
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);
} }
AssemblyItems ComputeMethod::findRepresentation(u256 const& _value) AssemblyItems ComputeMethod::findRepresentation(u256 const& _value)

View File

@ -60,7 +60,10 @@ public:
explicit ConstantOptimisationMethod(Params const& _params, u256 const& _value): explicit ConstantOptimisationMethod(Params const& _params, u256 const& _value):
m_params(_params), m_value(_value) {} m_params(_params), m_value(_value) {}
virtual bigint gasNeeded() = 0; 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: protected:
size_t dataSize() const { return std::max<size_t>(1, dev::bytesRequired(m_value)); } 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; return m_params.runs * _runGas + m_params.multiplicity * _repeatedDataGas + _uniqueDataGas;
} }
/// Replaces the constant by the code given in @a _replacement. /// Replaces all constants i by the code given in @a _replacement[i].
void replaceConstants(AssemblyItems& _items, AssemblyItems const& _replacement) const; static void replaceConstants(AssemblyItems& _items, std::map<u256, AssemblyItems> const& _replacement);
Params m_params; Params m_params;
u256 const& m_value; u256 const& m_value;
@ -100,7 +103,7 @@ public:
explicit LiteralMethod(Params const& _params, u256 const& _value): explicit LiteralMethod(Params const& _params, u256 const& _value):
ConstantOptimisationMethod(_params, _value) {} ConstantOptimisationMethod(_params, _value) {}
virtual bigint gasNeeded() override; 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: public:
explicit CodeCopyMethod(Params const& _params, u256 const& _value); explicit CodeCopyMethod(Params const& _params, u256 const& _value);
virtual bigint gasNeeded() override; virtual bigint gasNeeded() override;
virtual void execute(Assembly& _assembly, AssemblyItems& _items) override; virtual AssemblyItems execute(Assembly& _assembly) override;
protected: protected:
AssemblyItems m_copyRoutine; AssemblyItems const& copyRoutine() const;
}; };
/** /**
@ -130,9 +133,9 @@ public:
} }
virtual bigint gasNeeded() override { return gasNeeded(m_routine); } 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: protected: