Construct computation routine using Yul.

This commit is contained in:
chriseth 2019-05-14 15:32:02 +02:00
parent 80e5dd4b85
commit 0a98fd4c7c
2 changed files with 67 additions and 69 deletions

View File

@ -186,21 +186,15 @@ AssemblyItems const& CodeCopyMethod::copyRoutine()
return copyRoutine; return copyRoutine;
} }
AssemblyItems ComputeMethod::findRepresentation(u256 const& _value) AssemblyItems ComputeMethod::yulRoutineToAssemblyItems(string const& _routine) const
{ {
string routine = findRepresentationInternal(_value); if (_routine.empty())
if (routine.empty())
return {}; return {};
return yulRoutineToAssemblyItems(routine); string routine = "{ pop(" + _routine + ") }";
}
AssemblyItems ComputeMethod::yulRoutineToAssemblyItems(string _routine)
{
_routine = "{ pop(" + _routine + ") }";
langutil::ErrorList errors; langutil::ErrorList errors;
langutil::ErrorReporter errorReporter(errors); langutil::ErrorReporter errorReporter(errors);
auto scanner = make_shared<langutil::Scanner>(langutil::CharStream(_routine, "--CODEGEN--")); auto scanner = make_shared<langutil::Scanner>(langutil::CharStream(routine, "--CODEGEN--"));
auto parserResult = yul::Parser(errorReporter, yul::EVMDialect::strictAssemblyForEVM(m_params.evmVersion)).parse(scanner, false); auto parserResult = yul::Parser(errorReporter, yul::EVMDialect::strictAssemblyForEVM(m_params.evmVersion)).parse(scanner, false);
solAssert(parserResult, ""); solAssert(parserResult, "");
yul::AsmAnalysisInfo analysisInfo; yul::AsmAnalysisInfo analysisInfo;
@ -226,65 +220,64 @@ AssemblyItems ComputeMethod::yulRoutineToAssemblyItems(string _routine)
return {_asm.items().begin(), --_asm.items().end()}; return {_asm.items().begin(), --_asm.items().end()};
} }
string ComputeMethod::findRepresentationInternal(u256 const& _value) string ComputeMethod::findRepresentation(u256 const& _value)
{ {
return _value.str(); if (_value < 0x10000)
// if (_value < 0x10000) // Very small value, not worth computing
// // Very small value, not worth computing return _value.str();
// return AssemblyItems{_value}; else if (dev::bytesRequired(~_value) < dev::bytesRequired(_value))
// else if (dev::bytesRequired(~_value) < dev::bytesRequired(_value)) // Negated is shorter to represent
// // Negated is shorter to represent return "not(" + findRepresentation(~_value) + ")";
// return findRepresentation(~_value) + AssemblyItems{Instruction::NOT}; else
// else {
// { // Decompose value into a * 2**k + b where abs(b) << 2**k
// // Decompose value into a * 2**k + b where abs(b) << 2**k // Is not always better, try literal and decomposition method.
// // Is not always better, try literal and decomposition method. string routine{_value.str()};
// AssemblyItems routine{u256(_value)}; bigint bestGas = gasNeeded(routine);
// bigint bestGas = gasNeeded(routine); for (unsigned bits = 255; bits > 8 && m_maxSteps > 0; --bits)
// for (unsigned bits = 255; bits > 8 && m_maxSteps > 0; --bits) {
// { unsigned gapDetector = unsigned((_value >> (bits - 8)) & 0x1ff);
// unsigned gapDetector = unsigned((_value >> (bits - 8)) & 0x1ff); if (gapDetector != 0xff && gapDetector != 0x100)
// if (gapDetector != 0xff && gapDetector != 0x100) continue;
// continue;
// u256 powerOfTwo = u256(1) << bits; u256 powerOfTwo = u256(1) << bits;
// u256 upperPart = _value >> bits; u256 upperPart = _value >> bits;
// bigint lowerPart = _value & (powerOfTwo - 1); bigint lowerPart = _value & (powerOfTwo - 1);
// if ((powerOfTwo - lowerPart) < lowerPart) if ((powerOfTwo - lowerPart) < lowerPart)
// { {
// lowerPart = lowerPart - powerOfTwo; // make it negative lowerPart = lowerPart - powerOfTwo; // make it negative
// upperPart++; upperPart++;
// } }
// if (upperPart == 0) if (upperPart == 0)
// continue; continue;
// if (abs(lowerPart) >= (powerOfTwo >> 8)) if (abs(lowerPart) >= (powerOfTwo >> 8))
// continue; continue;
// AssemblyItems newRoutine; string newRoutine;
// if (lowerPart != 0) if (m_params.evmVersion.hasBitwiseShifting())
// newRoutine += findRepresentation(u256(abs(lowerPart))); newRoutine = "shl(" + to_string(bits) + ", " + findRepresentation(upperPart) + ")";
// if (m_params.evmVersion.hasBitwiseShifting()) else
// newRoutine += AssemblyItems{u256(1), u256(bits), Instruction::SHL}; {
// else newRoutine = "exp(2, " + to_string(bits) + ")";
// newRoutine += AssemblyItems{u256(bits), u256(2), Instruction::EXP}; if (upperPart != 1)
// if (upperPart != 1) newRoutine = "mul(" + findRepresentation(upperPart) + ", " + newRoutine + ")";
// newRoutine += findRepresentation(upperPart) + AssemblyItems{Instruction::MUL}; }
// if (lowerPart > 0) if (lowerPart > 0)
// newRoutine += AssemblyItems{Instruction::ADD}; newRoutine = "add(" + newRoutine + ", " + findRepresentation(u256(abs(lowerPart))) + ")";
// else if (lowerPart < 0) else if (lowerPart < 0)
// newRoutine.push_back(Instruction::SUB); newRoutine = "sub(" + newRoutine + ", " + findRepresentation(u256(abs(lowerPart))) + ")";
// if (m_maxSteps > 0) if (m_maxSteps > 0)
// m_maxSteps--; m_maxSteps--;
// bigint newGas = gasNeeded(newRoutine); bigint newGas = gasNeeded(newRoutine);
// if (newGas < bestGas) if (newGas < bestGas)
// { {
// bestGas = move(newGas); bestGas = move(newGas);
// routine = move(newRoutine); routine = move(newRoutine);
// } }
// } }
// return routine; return routine;
// } }
} }
bool ComputeMethod::checkRepresentation(u256 const& _value, AssemblyItems const& _routine) const bool ComputeMethod::checkRepresentation(u256 const& _value, AssemblyItems const& _routine) const
@ -353,6 +346,11 @@ bool ComputeMethod::checkRepresentation(u256 const& _value, AssemblyItems const&
return stack.size() == 1 && stack.front() == _value; return stack.size() == 1 && stack.front() == _value;
} }
bigint ComputeMethod::gasNeeded(string const& _routine) const
{
return gasNeeded(yulRoutineToAssemblyItems(_routine));
}
bigint ComputeMethod::gasNeeded(AssemblyItems const& _routine) const bigint ComputeMethod::gasNeeded(AssemblyItems const& _routine) const
{ {
size_t numExps = count(_routine.begin(), _routine.end(), Instruction::EXP); size_t numExps = count(_routine.begin(), _routine.end(), Instruction::EXP);

View File

@ -146,7 +146,7 @@ public:
explicit ComputeMethod(Params const& _params, u256 const& _value): explicit ComputeMethod(Params const& _params, u256 const& _value):
ConstantOptimisationMethod(_params, _value) ConstantOptimisationMethod(_params, _value)
{ {
m_routine = findRepresentation(m_value); m_routine = yulRoutineToAssemblyItems(findRepresentation(m_value));
assertThrow( assertThrow(
checkRepresentation(m_value, m_routine), checkRepresentation(m_value, m_routine),
OptimizerException, OptimizerException,
@ -161,12 +161,12 @@ public:
} }
protected: protected:
AssemblyItems yulRoutineToAssemblyItems(std::string const& _routine) const;
/// Tries to recursively find a way to compute @a _value. /// Tries to recursively find a way to compute @a _value.
AssemblyItems findRepresentation(u256 const& _value); std::string findRepresentation(u256 const& _value);
AssemblyItems yulRoutineToAssemblyItems(std::string _routine);
std::string findRepresentationInternal(u256 const& _value);
/// Recomputes the value from the calculated representation and checks for correctness. /// Recomputes the value from the calculated representation and checks for correctness.
bool checkRepresentation(u256 const& _value, AssemblyItems const& _routine) const; bool checkRepresentation(u256 const& _value, AssemblyItems const& _routine) const;
bigint gasNeeded(std::string const& _routine) const;
bigint gasNeeded(AssemblyItems const& _routine) const; bigint gasNeeded(AssemblyItems const& _routine) const;
/// Counter for the complexity of optimization, will stop when it reaches zero. /// Counter for the complexity of optimization, will stop when it reaches zero.