aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Changelog.md1
-rw-r--r--libevmasm/ConstantOptimiser.cpp4
-rw-r--r--libevmasm/ConstantOptimiser.h2
-rw-r--r--test/libsolidity/SolidityOptimizer.cpp62
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.