mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Construct computation routine using Yul.
This commit is contained in:
parent
80e5dd4b85
commit
0a98fd4c7c
@ -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);
|
||||
|
@ -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.
|
||||
|
Loading…
Reference in New Issue
Block a user