diff options
author | Paweł Bylica <pawel.bylica@imapp.pl> | 2015-05-20 23:34:09 +0800 |
---|---|---|
committer | Paweł Bylica <pawel.bylica@imapp.pl> | 2015-05-20 23:34:09 +0800 |
commit | b85345cc913a4c3713705925438d5069331aa6f4 (patch) | |
tree | 8f0cfbe73fecf9f95d2a131c0d4fce7c88c0a5da /libsolidity/SolidityOptimizer.cpp | |
parent | d5841327a2f0d8a990082bf4c16597e2b1f85926 (diff) | |
parent | b0d5cbf6983030c4e4fb48c45e1602880069b063 (diff) | |
download | dexon-solidity-b85345cc913a4c3713705925438d5069331aa6f4.tar dexon-solidity-b85345cc913a4c3713705925438d5069331aa6f4.tar.gz dexon-solidity-b85345cc913a4c3713705925438d5069331aa6f4.tar.bz2 dexon-solidity-b85345cc913a4c3713705925438d5069331aa6f4.tar.lz dexon-solidity-b85345cc913a4c3713705925438d5069331aa6f4.tar.xz dexon-solidity-b85345cc913a4c3713705925438d5069331aa6f4.tar.zst dexon-solidity-b85345cc913a4c3713705925438d5069331aa6f4.zip |
Merge remote-tracking branch 'upstream/develop' into feature/vm_gas_counter_refactor
Conflicts:
libethereum/ExtVM.cpp
libevm/SmartVM.h
libevm/VM.cpp
libevm/VM.h
libevm/VMFace.h
Diffstat (limited to 'libsolidity/SolidityOptimizer.cpp')
-rw-r--r-- | libsolidity/SolidityOptimizer.cpp | 140 |
1 files changed, 138 insertions, 2 deletions
diff --git a/libsolidity/SolidityOptimizer.cpp b/libsolidity/SolidityOptimizer.cpp index 3cb6a536..744fc48a 100644 --- a/libsolidity/SolidityOptimizer.cpp +++ b/libsolidity/SolidityOptimizer.cpp @@ -29,6 +29,7 @@ #include <libevmasm/CommonSubexpressionEliminator.h> #include <libevmasm/ControlFlowGraph.h> #include <libevmasm/Assembly.h> +#include <libevmasm/BlockDeduplicator.h> using namespace std; using namespace dev::eth; @@ -96,7 +97,7 @@ public: { eth::KnownState state; for (auto const& item: addDummyLocations(_input)) - state.feedItem(item); + state.feedItem(item, true); return state; } @@ -125,7 +126,7 @@ public: BOOST_CHECK_EQUAL_COLLECTIONS(_expectation.begin(), _expectation.end(), output.begin(), output.end()); } - void checkCFG(AssemblyItems const& _input, AssemblyItems const& _expectation) + AssemblyItems getCFG(AssemblyItems const& _input) { AssemblyItems output = _input; // Running it four times should be enough for these tests. @@ -138,6 +139,12 @@ public: back_inserter(optItems)); output = move(optItems); } + return output; + } + + void checkCFG(AssemblyItems const& _input, AssemblyItems const& _expectation) + { + AssemblyItems output = getCFG(_input); BOOST_CHECK_EQUAL_COLLECTIONS(_expectation.begin(), _expectation.end(), output.begin(), output.end()); } @@ -251,6 +258,106 @@ BOOST_AUTO_TEST_CASE(function_calls) compareVersions("f(uint256)", 36); } +BOOST_AUTO_TEST_CASE(storage_write_in_loops) +{ + char const* sourceCode = R"( + contract test { + uint d; + function f(uint a) returns (uint r) { + var x = d; + for (uint i = 1; i < a * a; i++) { + r = d; + d = i; + } + + } + } + )"; + compileBothVersions(sourceCode); + compareVersions("f(uint256)", 0); + compareVersions("f(uint256)", 10); + compareVersions("f(uint256)", 36); +} + +BOOST_AUTO_TEST_CASE(retain_information_in_branches) +{ + // This tests that the optimizer knows that we already have "z == sha3(y)" inside both branches. + char const* sourceCode = R"( + contract c { + bytes32 d; + uint a; + function f(uint x, bytes32 y) returns (uint r_a, bytes32 r_d) { + bytes32 z = sha3(y); + if (x > 8) { + z = sha3(y); + a = x; + } else { + z = sha3(y); + a = x; + } + r_a = a; + r_d = d; + } + } + )"; + compileBothVersions(sourceCode); + compareVersions("f(uint256,bytes32)", 0, "abc"); + compareVersions("f(uint256,bytes32)", 8, "def"); + compareVersions("f(uint256,bytes32)", 10, "ghi"); + + m_optimize = true; + bytes optimizedBytecode = compileAndRun(sourceCode, 0, "c"); + size_t numSHA3s = 0; + eth::eachInstruction(optimizedBytecode, [&](Instruction _instr, u256 const&) { + if (_instr == eth::Instruction::SHA3) + numSHA3s++; + }); + BOOST_CHECK_EQUAL(1, numSHA3s); +} + +BOOST_AUTO_TEST_CASE(store_tags_as_unions) +{ + // This calls the same function from two sources and both calls have a certain sha3 on + // the stack at the same position. + // Without storing tags as unions, the return from the shared function would not know where to + // jump and thus all jumpdests are forced to clear their state and we do not know about the + // sha3 anymore. + // Note that, for now, this only works if the functions have the same number of return + // parameters since otherwise, the return jump addresses are at different stack positions + // which triggers the "unknown jump target" situation. + char const* sourceCode = R"( + contract test { + bytes32 data; + function f(uint x, bytes32 y) external returns (uint r_a, bytes32 r_d) { + r_d = sha3(y); + shared(y); + r_d = sha3(y); + r_a = 5; + } + function g(uint x, bytes32 y) external returns (uint r_a, bytes32 r_d) { + r_d = sha3(y); + shared(y); + r_d = bytes32(uint(sha3(y)) + 2); + r_a = 7; + } + function shared(bytes32 y) internal { + data = sha3(y); + } + } + )"; + compileBothVersions(sourceCode); + compareVersions("f()", 7, "abc"); + + m_optimize = true; + bytes optimizedBytecode = compileAndRun(sourceCode, 0, "test"); + size_t numSHA3s = 0; + eth::eachInstruction(optimizedBytecode, [&](Instruction _instr, u256 const&) { + if (_instr == eth::Instruction::SHA3) + numSHA3s++; + }); + BOOST_CHECK_EQUAL(2, numSHA3s); +} + BOOST_AUTO_TEST_CASE(cse_intermediate_swap) { eth::KnownState state; @@ -868,6 +975,35 @@ BOOST_AUTO_TEST_CASE(control_flow_graph_do_not_remove_returned_to) checkCFG(input, {u256(2)}); } +BOOST_AUTO_TEST_CASE(block_deduplicator) +{ + AssemblyItems input{ + AssemblyItem(PushTag, 2), + AssemblyItem(PushTag, 1), + AssemblyItem(PushTag, 3), + u256(6), + eth::Instruction::SWAP3, + eth::Instruction::JUMP, + AssemblyItem(Tag, 1), + u256(6), + eth::Instruction::SWAP3, + eth::Instruction::JUMP, + AssemblyItem(Tag, 2), + u256(6), + eth::Instruction::SWAP3, + eth::Instruction::JUMP, + AssemblyItem(Tag, 3) + }; + BlockDeduplicator dedup(input); + dedup.deduplicate(); + + set<u256> pushTags; + for (AssemblyItem const& item: input) + if (item.type() == PushTag) + pushTags.insert(item.data()); + BOOST_CHECK_EQUAL(pushTags.size(), 2); +} + BOOST_AUTO_TEST_SUITE_END() } |