diff options
author | Yoichi Hirai <i@yoichihirai.com> | 2017-03-08 19:11:16 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-03-08 19:11:16 +0800 |
commit | 85411f4f677769f3ea1b69c49c44d9c08180dbd4 (patch) | |
tree | 7acfbf6140c925c48036eb527e4dd11d42283413 | |
parent | a1e350a4aeef11865d2deee5a4e59feb0625d053 (diff) | |
parent | 244b45e1ffe13cc12e7d6fd18467094b4bb0cb6a (diff) | |
download | dexon-solidity-85411f4f677769f3ea1b69c49c44d9c08180dbd4.tar dexon-solidity-85411f4f677769f3ea1b69c49c44d9c08180dbd4.tar.gz dexon-solidity-85411f4f677769f3ea1b69c49c44d9c08180dbd4.tar.bz2 dexon-solidity-85411f4f677769f3ea1b69c49c44d9c08180dbd4.tar.lz dexon-solidity-85411f4f677769f3ea1b69c49c44d9c08180dbd4.tar.xz dexon-solidity-85411f4f677769f3ea1b69c49c44d9c08180dbd4.tar.zst dexon-solidity-85411f4f677769f3ea1b69c49c44d9c08180dbd4.zip |
Merge pull request #1736 from ethereum/boundoptimizer
Add upper bound for computing constants.
-rw-r--r-- | Changelog.md | 1 | ||||
-rw-r--r-- | libevmasm/ConstantOptimiser.cpp | 4 | ||||
-rw-r--r-- | libevmasm/ConstantOptimiser.h | 2 | ||||
-rw-r--r-- | test/libsolidity/SolidityOptimizer.cpp | 62 |
4 files changed, 68 insertions, 1 deletions
diff --git a/Changelog.md b/Changelog.md index 8e11775b..ebd6f121 100644 --- a/Changelog.md +++ b/Changelog.md @@ -18,6 +18,7 @@ Bugfixes: * Type system: Correctly convert function argument types to pointers for member functions. * Inline assembly: Charge one stack slot for non-value types during analysis. * Assembly output: Print source location before the operation it refers to instead of after. + * Optimizer: Stop trying to optimize tricky constants after a while. ### 0.4.9 (2017-01-31) diff --git a/libevmasm/ConstantOptimiser.cpp b/libevmasm/ConstantOptimiser.cpp index 86244e17..a1dfd21c 100644 --- a/libevmasm/ConstantOptimiser.cpp +++ b/libevmasm/ConstantOptimiser.cpp @@ -194,7 +194,7 @@ AssemblyItems ComputeMethod::findRepresentation(u256 const& _value) // Is not always better, try literal and decomposition method. AssemblyItems routine{u256(_value)}; bigint bestGas = gasNeeded(routine); - for (unsigned bits = 255; bits > 8; --bits) + for (unsigned bits = 255; bits > 8 && m_maxSteps > 0; --bits) { unsigned gapDetector = unsigned(_value >> (bits - 8)) & 0x1ff; if (gapDetector != 0xff && gapDetector != 0x100) @@ -219,6 +219,8 @@ AssemblyItems ComputeMethod::findRepresentation(u256 const& _value) else if (lowerPart < 0) newRoutine.push_back(Instruction::SUB); + if (m_maxSteps > 0) + m_maxSteps--; bigint newGas = gasNeeded(newRoutine); if (newGas < bestGas) { diff --git a/libevmasm/ConstantOptimiser.h b/libevmasm/ConstantOptimiser.h index dfa2fbf8..4f12c49f 100644 --- a/libevmasm/ConstantOptimiser.h +++ b/libevmasm/ConstantOptimiser.h @@ -143,6 +143,8 @@ protected: AssemblyItems findRepresentation(u256 const& _value); bigint gasNeeded(AssemblyItems const& _routine); + /// Counter for the complexity of optimization, will stop when it reaches zero. + size_t m_maxSteps = 10000; AssemblyItems m_routine; }; diff --git a/test/libsolidity/SolidityOptimizer.cpp b/test/libsolidity/SolidityOptimizer.cpp index 2e2e0c6c..bcf6cd49 100644 --- a/test/libsolidity/SolidityOptimizer.cpp +++ b/test/libsolidity/SolidityOptimizer.cpp @@ -31,6 +31,7 @@ #include <boost/test/unit_test.hpp> #include <boost/lexical_cast.hpp> +#include <chrono> #include <string> #include <tuple> #include <memory> @@ -1234,6 +1235,67 @@ BOOST_AUTO_TEST_CASE(computing_constants) ) == optimizedBytecode.cend()); } + +BOOST_AUTO_TEST_CASE(constant_optimization_early_exit) +{ + // This tests that the constant optimizer does not try to find the best representation + // indefinitely but instead stops after some number of iterations. + char const* sourceCode = R"( + pragma solidity ^0.4.0; + + contract HexEncoding { + function hexEncodeTest(address addr) returns (bytes32 ret) { + uint x = uint(addr) / 2**32; + + // Nibble interleave + x = x & 0x00000000000000000000000000000000ffffffffffffffffffffffffffffffff; + x = (x | (x * 2**64)) & 0x0000000000000000ffffffffffffffff0000000000000000ffffffffffffffff; + x = (x | (x * 2**32)) & 0x00000000ffffffff00000000ffffffff00000000ffffffff00000000ffffffff; + x = (x | (x * 2**16)) & 0x0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff; + x = (x | (x * 2** 8)) & 0x00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff; + x = (x | (x * 2** 4)) & 0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f; + + // Hex encode + uint h = (x & 0x0808080808080808080808080808080808080808080808080808080808080808) / 8; + uint i = (x & 0x0404040404040404040404040404040404040404040404040404040404040404) / 4; + uint j = (x & 0x0202020202020202020202020202020202020202020202020202020202020202) / 2; + x = x + (h & (i | j)) * 0x27 + 0x3030303030303030303030303030303030303030303030303030303030303030; + + // Store and load next batch + assembly { + mstore(0, x) + } + x = uint(addr) * 2**96; + + // Nibble interleave + x = x & 0x00000000000000000000000000000000ffffffffffffffffffffffffffffffff; + x = (x | (x * 2**64)) & 0x0000000000000000ffffffffffffffff0000000000000000ffffffffffffffff; + x = (x | (x * 2**32)) & 0x00000000ffffffff00000000ffffffff00000000ffffffff00000000ffffffff; + x = (x | (x * 2**16)) & 0x0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff; + x = (x | (x * 2** 8)) & 0x00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff; + x = (x | (x * 2** 4)) & 0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f; + + // Hex encode + h = (x & 0x0808080808080808080808080808080808080808080808080808080808080808) / 8; + i = (x & 0x0404040404040404040404040404040404040404040404040404040404040404) / 4; + j = (x & 0x0202020202020202020202020202020202020202020202020202020202020202) / 2; + x = x + (h & (i | j)) * 0x27 + 0x3030303030303030303030303030303030303030303030303030303030303030; + + // Store and hash + assembly { + mstore(32, x) + ret := sha3(0, 40) + } + } + } + )"; + auto start = std::chrono::steady_clock::now(); + compileBothVersions(sourceCode); + double duration = std::chrono::duration<double>(std::chrono::steady_clock::now() - start).count(); + BOOST_CHECK_MESSAGE(duration < 20, "Compilation of constants took longer than 20 seconds."); + compareVersions("hexEncodeTest(address)", u256(0x123456789)); +} + BOOST_AUTO_TEST_CASE(inconsistency) { // This is a test of a bug in the optimizer. |