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;
}
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 yulRoutineToAssemblyItems(routine);
}
AssemblyItems ComputeMethod::yulRoutineToAssemblyItems(string _routine)
{
_routine = "{ pop(" + _routine + ") }";
string routine = "{ pop(" + _routine + ") }";
langutil::ErrorList 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);
solAssert(parserResult, "");
yul::AsmAnalysisInfo analysisInfo;
@ -226,65 +220,64 @@ AssemblyItems ComputeMethod::yulRoutineToAssemblyItems(string _routine)
return {_asm.items().begin(), --_asm.items().end()};
}
string ComputeMethod::findRepresentationInternal(u256 const& _value)
string ComputeMethod::findRepresentation(u256 const& _value)
{
if (_value < 0x10000)
// Very small value, not worth computing
return _value.str();
// if (_value < 0x10000)
// // Very small value, not worth computing
// return AssemblyItems{_value};
// else if (dev::bytesRequired(~_value) < dev::bytesRequired(_value))
// // Negated is shorter to represent
// return findRepresentation(~_value) + AssemblyItems{Instruction::NOT};
// else
// {
// // Decompose value into a * 2**k + b where abs(b) << 2**k
// // Is not always better, try literal and decomposition method.
// AssemblyItems routine{u256(_value)};
// bigint bestGas = gasNeeded(routine);
// for (unsigned bits = 255; bits > 8 && m_maxSteps > 0; --bits)
// {
// unsigned gapDetector = unsigned((_value >> (bits - 8)) & 0x1ff);
// if (gapDetector != 0xff && gapDetector != 0x100)
// continue;
else if (dev::bytesRequired(~_value) < dev::bytesRequired(_value))
// Negated is shorter to represent
return "not(" + findRepresentation(~_value) + ")";
else
{
// Decompose value into a * 2**k + b where abs(b) << 2**k
// Is not always better, try literal and decomposition method.
string routine{_value.str()};
bigint bestGas = gasNeeded(routine);
for (unsigned bits = 255; bits > 8 && m_maxSteps > 0; --bits)
{
unsigned gapDetector = unsigned((_value >> (bits - 8)) & 0x1ff);
if (gapDetector != 0xff && gapDetector != 0x100)
continue;
// u256 powerOfTwo = u256(1) << bits;
// u256 upperPart = _value >> bits;
// bigint lowerPart = _value & (powerOfTwo - 1);
// if ((powerOfTwo - lowerPart) < lowerPart)
// {
// lowerPart = lowerPart - powerOfTwo; // make it negative
// upperPart++;
// }
// if (upperPart == 0)
// continue;
// if (abs(lowerPart) >= (powerOfTwo >> 8))
// continue;
u256 powerOfTwo = u256(1) << bits;
u256 upperPart = _value >> bits;
bigint lowerPart = _value & (powerOfTwo - 1);
if ((powerOfTwo - lowerPart) < lowerPart)
{
lowerPart = lowerPart - powerOfTwo; // make it negative
upperPart++;
}
if (upperPart == 0)
continue;
if (abs(lowerPart) >= (powerOfTwo >> 8))
continue;
// AssemblyItems newRoutine;
// if (lowerPart != 0)
// newRoutine += findRepresentation(u256(abs(lowerPart)));
// if (m_params.evmVersion.hasBitwiseShifting())
// newRoutine += AssemblyItems{u256(1), u256(bits), Instruction::SHL};
// else
// newRoutine += AssemblyItems{u256(bits), u256(2), Instruction::EXP};
// if (upperPart != 1)
// newRoutine += findRepresentation(upperPart) + AssemblyItems{Instruction::MUL};
// if (lowerPart > 0)
// newRoutine += AssemblyItems{Instruction::ADD};
// else if (lowerPart < 0)
// newRoutine.push_back(Instruction::SUB);
string newRoutine;
if (m_params.evmVersion.hasBitwiseShifting())
newRoutine = "shl(" + to_string(bits) + ", " + findRepresentation(upperPart) + ")";
else
{
newRoutine = "exp(2, " + to_string(bits) + ")";
if (upperPart != 1)
newRoutine = "mul(" + findRepresentation(upperPart) + ", " + newRoutine + ")";
}
if (lowerPart > 0)
newRoutine = "add(" + newRoutine + ", " + findRepresentation(u256(abs(lowerPart))) + ")";
else if (lowerPart < 0)
newRoutine = "sub(" + newRoutine + ", " + findRepresentation(u256(abs(lowerPart))) + ")";
// if (m_maxSteps > 0)
// m_maxSteps--;
// bigint newGas = gasNeeded(newRoutine);
// if (newGas < bestGas)
// {
// bestGas = move(newGas);
// routine = move(newRoutine);
// }
// }
// return routine;
// }
if (m_maxSteps > 0)
m_maxSteps--;
bigint newGas = gasNeeded(newRoutine);
if (newGas < bestGas)
{
bestGas = move(newGas);
routine = move(newRoutine);
}
}
return routine;
}
}
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;
}
bigint ComputeMethod::gasNeeded(string const& _routine) const
{
return gasNeeded(yulRoutineToAssemblyItems(_routine));
}
bigint ComputeMethod::gasNeeded(AssemblyItems const& _routine) const
{
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):
ConstantOptimisationMethod(_params, _value)
{
m_routine = findRepresentation(m_value);
m_routine = yulRoutineToAssemblyItems(findRepresentation(m_value));
assertThrow(
checkRepresentation(m_value, m_routine),
OptimizerException,
@ -161,12 +161,12 @@ public:
}
protected:
AssemblyItems yulRoutineToAssemblyItems(std::string const& _routine) const;
/// Tries to recursively find a way to compute @a _value.
AssemblyItems findRepresentation(u256 const& _value);
AssemblyItems yulRoutineToAssemblyItems(std::string _routine);
std::string findRepresentationInternal(u256 const& _value);
std::string findRepresentation(u256 const& _value);
/// Recomputes the value from the calculated representation and checks for correctness.
bool checkRepresentation(u256 const& _value, AssemblyItems const& _routine) const;
bigint gasNeeded(std::string const& _routine) const;
bigint gasNeeded(AssemblyItems const& _routine) const;
/// Counter for the complexity of optimization, will stop when it reaches zero.