mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Optimize constant optimization.
This commit is contained in:
parent
f1a4976ce6
commit
da5e171f3b
@ -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)
|
||||
|
@ -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:
|
||||
|
Loading…
Reference in New Issue
Block a user