From 05dac999223220fdb54c0d28781b3ef1d621061d Mon Sep 17 00:00:00 2001
From: chriseth <c@ethdev.com>
Date: Fri, 3 Mar 2017 16:17:00 +0100
Subject: Tests for optimizing constants.

---
 test/libsolidity/SolidityOptimizer.cpp | 62 ++++++++++++++++++++++++++++++++++
 1 file changed, 62 insertions(+)

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.
-- 
cgit v1.2.3