diff --git a/libevmasm/ConstantOptimiser.cpp b/libevmasm/ConstantOptimiser.cpp index 124d72e8b..4d99a59d5 100644 --- a/libevmasm/ConstantOptimiser.cpp +++ b/libevmasm/ConstantOptimiser.cpp @@ -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::CharStream(_routine, "--CODEGEN--")); + auto scanner = make_shared(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) { - 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; + if (_value < 0x10000) + // Very small value, not worth computing + return _value.str(); + 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); diff --git a/libevmasm/ConstantOptimiser.h b/libevmasm/ConstantOptimiser.h index 90228954e..ee76685f8 100644 --- a/libevmasm/ConstantOptimiser.h +++ b/libevmasm/ConstantOptimiser.h @@ -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.