diff options
author | Paweł Bylica <pawel.bylica@imapp.pl> | 2014-12-19 20:58:22 +0800 |
---|---|---|
committer | Paweł Bylica <pawel.bylica@imapp.pl> | 2014-12-19 20:58:22 +0800 |
commit | c6d2c2392bd3f36f4539d990f60f9136e158d136 (patch) | |
tree | c1b6875165493b33752d9c283a00643b031c60e7 /SolidityOptimizer.cpp | |
parent | 180b0fa9e3aab595048d171ff4556a769f85dd1e (diff) | |
parent | 69319de1db7daedd24b0ac00a8b245bbd9f6042e (diff) | |
download | dexon-solidity-c6d2c2392bd3f36f4539d990f60f9136e158d136.tar.gz dexon-solidity-c6d2c2392bd3f36f4539d990f60f9136e158d136.tar.zst dexon-solidity-c6d2c2392bd3f36f4539d990f60f9136e158d136.zip |
Merge branch 'develop-evmcc' into pr-jit
Conflicts:
windows/Eth.vcxproj
windows/TestEthereum.vcxproj
Diffstat (limited to 'SolidityOptimizer.cpp')
-rw-r--r-- | SolidityOptimizer.cpp | 146 |
1 files changed, 146 insertions, 0 deletions
diff --git a/SolidityOptimizer.cpp b/SolidityOptimizer.cpp new file mode 100644 index 00000000..ef5c6f9b --- /dev/null +++ b/SolidityOptimizer.cpp @@ -0,0 +1,146 @@ + +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. +*/ +/** + * @author Christian <c@ethdev.com> + * @date 2014 + * Tests for the Solidity optimizer. + */ + +#include <string> +#include <tuple> +#include <boost/test/unit_test.hpp> +#include <boost/lexical_cast.hpp> +#include <test/solidityExecutionFramework.h> + +using namespace std; + +namespace dev +{ +namespace solidity +{ +namespace test +{ + +class OptimizerTestFramework: public ExecutionFramework +{ +public: + OptimizerTestFramework() { } + /// Compiles the source code with and without optimizing. + void compileBothVersions(unsigned _expectedSizeDecrease, std::string const& _sourceCode, u256 const& _value = 0, std::string const& _contractName = "") { + m_optimize = false; + bytes nonOptimizedBytecode = compileAndRun(_sourceCode, _value, _contractName); + m_nonOptimizedContract = m_contractAddress; + m_optimize = true; + bytes optimizedBytecode = compileAndRun(_sourceCode, _value, _contractName); + int sizeDiff = nonOptimizedBytecode.size() - optimizedBytecode.size(); + BOOST_CHECK_MESSAGE(sizeDiff == int(_expectedSizeDecrease), "Bytecode did only shrink by " + + boost::lexical_cast<string>(sizeDiff) + " bytes, expected: " + + boost::lexical_cast<string>(_expectedSizeDecrease)); + m_optimizedContract = m_contractAddress; + } + + template <class... Args> + void compareVersions(byte _index, Args const&... _arguments) + { + m_contractAddress = m_nonOptimizedContract; + bytes nonOptimizedOutput = callContractFunction(_index, _arguments...); + m_contractAddress = m_optimizedContract; + bytes optimizedOutput = callContractFunction(_index, _arguments...); + BOOST_CHECK_MESSAGE(nonOptimizedOutput == optimizedOutput, "Computed values do not match." + "\nNon-Optimized: " + toHex(nonOptimizedOutput) + + "\nOptimized: " + toHex(optimizedOutput)); + } + +protected: + Address m_optimizedContract; + Address m_nonOptimizedContract; +}; + +BOOST_FIXTURE_TEST_SUITE(SolidityOptimizer, OptimizerTestFramework) + +BOOST_AUTO_TEST_CASE(smoke_test) +{ + char const* sourceCode = R"( + contract test { + function f(uint a) returns (uint b) { + return a; + } + })"; + compileBothVersions(4, sourceCode); + compareVersions(0, u256(7)); +} + +BOOST_AUTO_TEST_CASE(large_integers) +{ + char const* sourceCode = R"( + contract test { + function f() returns (uint a, uint b) { + a = 0x234234872642837426347000000; + b = 0x110000000000000000000000002; + } + })"; + compileBothVersions(28, sourceCode); + compareVersions(0); +} + +BOOST_AUTO_TEST_CASE(invariants) +{ + char const* sourceCode = R"( + contract test { + function f(uint a) returns (uint b) { + return (((a + (1 - 1)) ^ 0) | 0) & (uint(0) - 1); + } + })"; + compileBothVersions(28, sourceCode); + compareVersions(0, u256(0x12334664)); +} + +BOOST_AUTO_TEST_CASE(unused_expressions) +{ + char const* sourceCode = R"( + contract test { + uint data; + function f() returns (uint a, uint b) { + 10 + 20; + data; + } + })"; + compileBothVersions(11, sourceCode); + compareVersions(0); +} + +BOOST_AUTO_TEST_CASE(constant_folding_both_sides) +{ + // if constants involving the same associative and commutative operator are applied from both + // sides, the operator should be applied only once, because the expression compiler + // (even in non-optimized mode) pushes literals as late as possible + char const* sourceCode = R"( + contract test { + function f(uint x) returns (uint y) { + return 98 ^ (7 * ((1 | (x | 1000)) * 40) ^ 102); + } + })"; + compileBothVersions(31, sourceCode); + compareVersions(0); +} + +BOOST_AUTO_TEST_SUITE_END() + +} +} +} // end namespaces |