From 0934d0e943765c7c87cf1b3da43aa876f4f1e469 Mon Sep 17 00:00:00 2001 From: chriseth Date: Thu, 19 Mar 2015 18:11:58 +0100 Subject: Code generation part 2. --- SolidityOptimizer.cpp | 163 +++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 140 insertions(+), 23 deletions(-) (limited to 'SolidityOptimizer.cpp') diff --git a/SolidityOptimizer.cpp b/SolidityOptimizer.cpp index 85b77d21..9c6a4e36 100644 --- a/SolidityOptimizer.cpp +++ b/SolidityOptimizer.cpp @@ -26,8 +26,11 @@ #include #include #include +#include +#include using namespace std; +using namespace dev::eth; namespace dev { @@ -41,16 +44,21 @@ 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 = "") { + void compileBothVersions( + 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 shrank by " - + boost::lexical_cast(sizeDiff) + " bytes, expected: " - + boost::lexical_cast(_expectedSizeDecrease)); + BOOST_CHECK_MESSAGE( + nonOptimizedBytecode.size() > optimizedBytecode.size(), + "Optimizer did not reduce bytecode size." + ); m_optimizedContract = m_contractAddress; } @@ -81,24 +89,11 @@ BOOST_AUTO_TEST_CASE(smoke_test) return a; } })"; - compileBothVersions(29, sourceCode); + compileBothVersions(sourceCode); compareVersions("f(uint256)", u256(7)); } -BOOST_AUTO_TEST_CASE(large_integers) -{ - char const* sourceCode = R"( - contract test { - function f() returns (uint a, uint b) { - a = 0x234234872642837426347000000; - b = 0x10000000000000000000000002; - } - })"; - compileBothVersions(36, sourceCode); - compareVersions("f()"); -} - -BOOST_AUTO_TEST_CASE(invariants) +BOOST_AUTO_TEST_CASE(identities) { char const* sourceCode = R"( contract test { @@ -106,7 +101,7 @@ BOOST_AUTO_TEST_CASE(invariants) return int(0) | (int(1) * (int(0) ^ (0 + a))); } })"; - compileBothVersions(41, sourceCode); + compileBothVersions(sourceCode); compareVersions("f(uint256)", u256(0x12334664)); } @@ -120,7 +115,7 @@ BOOST_AUTO_TEST_CASE(unused_expressions) data; } })"; - compileBothVersions(36, sourceCode); + compileBothVersions(sourceCode); compareVersions("f()"); } @@ -135,10 +130,132 @@ BOOST_AUTO_TEST_CASE(constant_folding_both_sides) return 98 ^ (7 * ((1 | (x | 1000)) * 40) ^ 102); } })"; - compileBothVersions(37, sourceCode); + compileBothVersions(sourceCode); + compareVersions("f(uint256)"); +} + +BOOST_AUTO_TEST_CASE(storage_access) +{ + char const* sourceCode = R"( + contract test { + uint8[40] data; + function f(uint x) returns (uint y) { + data[2] = data[7] = uint8(x); + data[4] = data[2] * 10 + data[3]; + } + } + )"; + compileBothVersions(sourceCode); compareVersions("f(uint256)"); } +BOOST_AUTO_TEST_CASE(array_copy) +{ + char const* sourceCode = R"( + contract test { + bytes2[] data1; + bytes5[] data2; + function f(uint x) returns (uint l, uint y) { + for (uint i = 0; i < msg.data.length; ++i) + data1[i] = msg.data[i]; + data2 = data1; + l = data2.length; + y = uint(data2[x]); + } + } + )"; + compileBothVersions(sourceCode); + compareVersions("f(uint256)", 0); + compareVersions("f(uint256)", 10); + compareVersions("f(uint256)", 36); +} + +BOOST_AUTO_TEST_CASE(function_calls) +{ + char const* sourceCode = R"( + contract test { + function f1(uint x) returns (uint) { return x*x; } + function f(uint x) returns (uint) { return f1(7+x) - this.f1(x**9); } + } + )"; + compileBothVersions(sourceCode); + compareVersions("f(uint256)", 0); + compareVersions("f(uint256)", 10); + compareVersions("f(uint256)", 36); +} + +BOOST_AUTO_TEST_CASE(cse_intermediate_swap) +{ + eth::CommonSubexpressionEliminator cse; + AssemblyItems input{ + Instruction::SWAP1, Instruction::POP, Instruction::ADD, u256(0), Instruction::SWAP1, + Instruction::SLOAD, Instruction::SWAP1, u256(100), Instruction::EXP, Instruction::SWAP1, + Instruction::DIV, u256(0xff), Instruction::AND + }; + BOOST_REQUIRE(cse.feedItems(input.begin(), input.end()) == input.end()); + AssemblyItems output = cse.getOptimizedItems(); + BOOST_CHECK(!output.empty()); +} + +BOOST_AUTO_TEST_CASE(cse_negative_stack_access) +{ + eth::CommonSubexpressionEliminator cse; + AssemblyItems input{AssemblyItem(Instruction::DUP2), AssemblyItem(u256(0))}; + BOOST_REQUIRE(cse.feedItems(input.begin(), input.end()) == input.end()); + AssemblyItems output = cse.getOptimizedItems(); + BOOST_CHECK_EQUAL_COLLECTIONS(input.begin(), input.end(), output.begin(), output.end()); +} + +BOOST_AUTO_TEST_CASE(cse_negative_stack_end) +{ + eth::CommonSubexpressionEliminator cse; + AssemblyItems input{ + AssemblyItem(Instruction::ADD) + }; + BOOST_REQUIRE(cse.feedItems(input.begin(), input.end()) == input.end()); + AssemblyItems output = cse.getOptimizedItems(); + BOOST_CHECK_EQUAL_COLLECTIONS(input.begin(), input.end(), output.begin(), output.end()); +} + +BOOST_AUTO_TEST_CASE(cse_intermediate_negative_stack) +{ + eth::CommonSubexpressionEliminator cse; + AssemblyItems input{ + AssemblyItem(Instruction::ADD), + AssemblyItem(u256(1)), + AssemblyItem(Instruction::DUP2) + }; + BOOST_REQUIRE(cse.feedItems(input.begin(), input.end()) == input.end()); + AssemblyItems output = cse.getOptimizedItems(); + BOOST_CHECK_EQUAL_COLLECTIONS(input.begin(), input.end(), output.begin(), output.end()); +} + +BOOST_AUTO_TEST_CASE(cse_pop) +{ + eth::CommonSubexpressionEliminator cse; + AssemblyItems input{ + AssemblyItem(Instruction::POP) + }; + BOOST_REQUIRE(cse.feedItems(input.begin(), input.end()) == input.end()); + AssemblyItems output = cse.getOptimizedItems(); + BOOST_CHECK_EQUAL_COLLECTIONS(input.begin(), input.end(), output.begin(), output.end()); +} + +BOOST_AUTO_TEST_CASE(cse_unneeded_items) +{ + eth::CommonSubexpressionEliminator cse; + AssemblyItems input{ + AssemblyItem(Instruction::ADD), + AssemblyItem(Instruction::SWAP1), + AssemblyItem(Instruction::POP), + AssemblyItem(u256(7)), + AssemblyItem(u256(8)), + }; + BOOST_REQUIRE(cse.feedItems(input.begin(), input.end()) == input.end()); + AssemblyItems output = cse.getOptimizedItems(); + BOOST_CHECK_EQUAL_COLLECTIONS(input.begin(), input.end(), output.begin(), output.end()); +} + BOOST_AUTO_TEST_SUITE_END() } -- cgit v1.2.3 From 782e69fbe406de3b4924737b3a3120308a0e096a Mon Sep 17 00:00:00 2001 From: chriseth Date: Fri, 20 Mar 2015 22:39:42 +0100 Subject: Optimizing various single operations. --- SolidityOptimizer.cpp | 78 +++++++++++++++++++++++++++------------------------ 1 file changed, 42 insertions(+), 36 deletions(-) (limited to 'SolidityOptimizer.cpp') diff --git a/SolidityOptimizer.cpp b/SolidityOptimizer.cpp index 9c6a4e36..2ced9743 100644 --- a/SolidityOptimizer.cpp +++ b/SolidityOptimizer.cpp @@ -74,6 +74,14 @@ public: "\nOptimized: " + toHex(optimizedOutput)); } + void checkCSE(AssemblyItems const& _input, AssemblyItems const& _expectation) + { + eth::CommonSubexpressionEliminator cse; + BOOST_REQUIRE(cse.feedItems(_input.begin(), _input.end()) == _input.end()); + AssemblyItems output = cse.getOptimizedItems(); + BOOST_CHECK_EQUAL_COLLECTIONS(_expectation.begin(), _expectation.end(), output.begin(), output.end()); + } + protected: Address m_optimizedContract; Address m_nonOptimizedContract; @@ -199,61 +207,59 @@ BOOST_AUTO_TEST_CASE(cse_intermediate_swap) BOOST_AUTO_TEST_CASE(cse_negative_stack_access) { - eth::CommonSubexpressionEliminator cse; - AssemblyItems input{AssemblyItem(Instruction::DUP2), AssemblyItem(u256(0))}; - BOOST_REQUIRE(cse.feedItems(input.begin(), input.end()) == input.end()); - AssemblyItems output = cse.getOptimizedItems(); - BOOST_CHECK_EQUAL_COLLECTIONS(input.begin(), input.end(), output.begin(), output.end()); + AssemblyItems input{Instruction::DUP2, u256(0)}; + checkCSE(input, input); } BOOST_AUTO_TEST_CASE(cse_negative_stack_end) { - eth::CommonSubexpressionEliminator cse; - AssemblyItems input{ - AssemblyItem(Instruction::ADD) - }; - BOOST_REQUIRE(cse.feedItems(input.begin(), input.end()) == input.end()); - AssemblyItems output = cse.getOptimizedItems(); - BOOST_CHECK_EQUAL_COLLECTIONS(input.begin(), input.end(), output.begin(), output.end()); + AssemblyItems input{Instruction::ADD}; + checkCSE(input, input); } BOOST_AUTO_TEST_CASE(cse_intermediate_negative_stack) { - eth::CommonSubexpressionEliminator cse; - AssemblyItems input{ - AssemblyItem(Instruction::ADD), - AssemblyItem(u256(1)), - AssemblyItem(Instruction::DUP2) - }; - BOOST_REQUIRE(cse.feedItems(input.begin(), input.end()) == input.end()); - AssemblyItems output = cse.getOptimizedItems(); - BOOST_CHECK_EQUAL_COLLECTIONS(input.begin(), input.end(), output.begin(), output.end()); + AssemblyItems input{Instruction::ADD, u256(1), Instruction::DUP1}; + checkCSE(input, input); } BOOST_AUTO_TEST_CASE(cse_pop) { - eth::CommonSubexpressionEliminator cse; + checkCSE({Instruction::POP}, {Instruction::POP}); +} + +BOOST_AUTO_TEST_CASE(cse_unneeded_items) +{ AssemblyItems input{ - AssemblyItem(Instruction::POP) + Instruction::ADD, + Instruction::SWAP1, + Instruction::POP, + u256(7), + u256(8), }; - BOOST_REQUIRE(cse.feedItems(input.begin(), input.end()) == input.end()); - AssemblyItems output = cse.getOptimizedItems(); - BOOST_CHECK_EQUAL_COLLECTIONS(input.begin(), input.end(), output.begin(), output.end()); + checkCSE(input, input); } -BOOST_AUTO_TEST_CASE(cse_unneeded_items) +BOOST_AUTO_TEST_CASE(cse_invariants) { - eth::CommonSubexpressionEliminator cse; AssemblyItems input{ - AssemblyItem(Instruction::ADD), - AssemblyItem(Instruction::SWAP1), - AssemblyItem(Instruction::POP), - AssemblyItem(u256(7)), - AssemblyItem(u256(8)), + Instruction::DUP1, + Instruction::DUP1, + u256(0), + Instruction::OR, + Instruction::OR }; - BOOST_REQUIRE(cse.feedItems(input.begin(), input.end()) == input.end()); - AssemblyItems output = cse.getOptimizedItems(); - BOOST_CHECK_EQUAL_COLLECTIONS(input.begin(), input.end(), output.begin(), output.end()); + checkCSE(input, {Instruction::DUP1}); +} + +BOOST_AUTO_TEST_CASE(cse_subself) +{ + checkCSE({Instruction::DUP1, Instruction::SUB}, {Instruction::POP, u256(0)}); +} + +BOOST_AUTO_TEST_CASE(cse_subother) +{ + checkCSE({Instruction::SUB}, {Instruction::SUB}); } BOOST_AUTO_TEST_SUITE_END() -- cgit v1.2.3 From 4e20d0fb6da983ce8716b7710a124e44226a16b0 Mon Sep 17 00:00:00 2001 From: chriseth Date: Mon, 23 Mar 2015 13:09:25 +0100 Subject: Pattern matching for expression simplification. --- SolidityOptimizer.cpp | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) (limited to 'SolidityOptimizer.cpp') diff --git a/SolidityOptimizer.cpp b/SolidityOptimizer.cpp index 2ced9743..2d5cff7a 100644 --- a/SolidityOptimizer.cpp +++ b/SolidityOptimizer.cpp @@ -240,6 +240,12 @@ BOOST_AUTO_TEST_CASE(cse_unneeded_items) checkCSE(input, input); } +BOOST_AUTO_TEST_CASE(cse_constant_addition) +{ + AssemblyItems input{u256(7), u256(8), Instruction::ADD}; + checkCSE(input, {u256(7 + 8)}); +} + BOOST_AUTO_TEST_CASE(cse_invariants) { AssemblyItems input{ @@ -262,6 +268,41 @@ BOOST_AUTO_TEST_CASE(cse_subother) checkCSE({Instruction::SUB}, {Instruction::SUB}); } +BOOST_AUTO_TEST_CASE(cse_double_negation) +{ + checkCSE({Instruction::DUP5, Instruction::NOT, Instruction::NOT}, {Instruction::DUP5}); +} + +BOOST_AUTO_TEST_CASE(cse_associativity) +{ + AssemblyItems input{ + Instruction::DUP1, + Instruction::DUP1, + u256(0), + Instruction::OR, + Instruction::OR + }; + checkCSE(input, {Instruction::DUP1}); +} + +BOOST_AUTO_TEST_CASE(cse_associativity2) +{ + AssemblyItems input{ + u256(0), + Instruction::DUP2, + u256(2), + u256(1), + Instruction::DUP6, + Instruction::ADD, + u256(2), + Instruction::ADD, + Instruction::ADD, + Instruction::ADD, + Instruction::ADD + }; + checkCSE(input, {Instruction::DUP2, Instruction::DUP2, Instruction::ADD, u256(5), Instruction::ADD}); +} + BOOST_AUTO_TEST_SUITE_END() } -- cgit v1.2.3 From 1391b58e53cdc3f163b81a972f0e798b5f7a8980 Mon Sep 17 00:00:00 2001 From: chriseth Date: Tue, 24 Mar 2015 14:53:15 +0100 Subject: Storage access optimisation. --- SolidityOptimizer.cpp | 180 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 180 insertions(+) (limited to 'SolidityOptimizer.cpp') diff --git a/SolidityOptimizer.cpp b/SolidityOptimizer.cpp index 2d5cff7a..de4cac8f 100644 --- a/SolidityOptimizer.cpp +++ b/SolidityOptimizer.cpp @@ -303,6 +303,186 @@ BOOST_AUTO_TEST_CASE(cse_associativity2) checkCSE(input, {Instruction::DUP2, Instruction::DUP2, Instruction::ADD, u256(5), Instruction::ADD}); } +BOOST_AUTO_TEST_CASE(cse_storage) +{ + AssemblyItems input{ + u256(0), + Instruction::SLOAD, + u256(0), + Instruction::SLOAD, + Instruction::ADD, + u256(0), + Instruction::SSTORE + }; + checkCSE(input, { + u256(0), + Instruction::DUP1, + Instruction::SLOAD, + Instruction::DUP1, + Instruction::ADD, + Instruction::SWAP1, + Instruction::SSTORE + }); +} + +BOOST_AUTO_TEST_CASE(cse_noninterleaved_storage) +{ + // two stores to the same location should be replaced by only one store, even if we + // read in the meantime + AssemblyItems input{ + u256(7), + Instruction::DUP2, + Instruction::SSTORE, + Instruction::DUP1, + Instruction::SLOAD, + u256(8), + Instruction::DUP3, + Instruction::SSTORE + }; + checkCSE(input, { + u256(8), + Instruction::DUP2, + Instruction::SSTORE, + u256(7) + }); +} + +BOOST_AUTO_TEST_CASE(cse_interleaved_storage) +{ + // stores and reads to/from two unknown locations, should not optimize away the first store + AssemblyItems input{ + u256(7), + Instruction::DUP2, + Instruction::SSTORE, // store to "DUP1" + Instruction::DUP2, + Instruction::SLOAD, // read from "DUP2", might be equal to "DUP1" + u256(0), + Instruction::DUP3, + Instruction::SSTORE // store different value to "DUP1" + }; + checkCSE(input, input); +} + +BOOST_AUTO_TEST_CASE(cse_interleaved_storage_same_value) +{ + // stores and reads to/from two unknown locations, should not optimize away the first store + // but it should optimize away the second, since we already know the value will be the same + AssemblyItems input{ + u256(7), + Instruction::DUP2, + Instruction::SSTORE, // store to "DUP1" + Instruction::DUP2, + Instruction::SLOAD, // read from "DUP2", might be equal to "DUP1" + u256(6), + u256(1), + Instruction::ADD, + Instruction::DUP3, + Instruction::SSTORE // store same value to "DUP1" + }; + checkCSE(input, { + u256(7), + Instruction::DUP2, + Instruction::SSTORE, + Instruction::DUP2, + Instruction::SLOAD + }); +} + +BOOST_AUTO_TEST_CASE(cse_interleaved_storage_at_known_location) +{ + // stores and reads to/from two known locations, should optimize away the first store, + // because we know that the location is different + AssemblyItems input{ + u256(0x70), + u256(1), + Instruction::SSTORE, // store to 1 + u256(2), + Instruction::SLOAD, // read from 2, is different from 1 + u256(0x90), + u256(1), + Instruction::SSTORE // store different value at 1 + }; + checkCSE(input, { + u256(2), + Instruction::SLOAD, + u256(0x90), + u256(1), + Instruction::SSTORE + }); +} + +BOOST_AUTO_TEST_CASE(cse_interleaved_storage_at_known_location_offset) +{ + // stores and reads to/from two locations which are known to be different, + // should optimize away the first store, because we know that the location is different + AssemblyItems input{ + u256(0x70), + Instruction::DUP2, + u256(1), + Instruction::ADD, + Instruction::SSTORE, // store to "DUP1"+1 + Instruction::DUP1, + u256(2), + Instruction::ADD, + Instruction::SLOAD, // read from "DUP1"+2, is different from "DUP1"+1 + u256(0x90), + Instruction::DUP3, + u256(1), + Instruction::ADD, + Instruction::SSTORE // store different value at "DUP1"+1 + }; + checkCSE(input, { + u256(2), + Instruction::DUP2, + Instruction::ADD, + Instruction::SLOAD, + u256(0x90), + u256(1), + Instruction::DUP4, + Instruction::ADD, + Instruction::SSTORE + }); +} + +BOOST_AUTO_TEST_CASE(cse_deep_stack) +{ + AssemblyItems input{ + Instruction::ADD, + Instruction::SWAP1, + Instruction::POP, + Instruction::SWAP8, + Instruction::POP, + Instruction::SWAP8, + Instruction::POP, + Instruction::SWAP8, + Instruction::SWAP5, + Instruction::POP, + Instruction::POP, + Instruction::POP, + Instruction::POP, + Instruction::POP, + }; + checkCSE(input, { + Instruction::SWAP4, + Instruction::SWAP12, + Instruction::SWAP3, + Instruction::SWAP11, + Instruction::POP, + Instruction::SWAP1, + Instruction::SWAP3, + Instruction::ADD, + Instruction::SWAP8, + Instruction::POP, + Instruction::SWAP6, + Instruction::POP, + Instruction::POP, + Instruction::POP, + Instruction::POP, + Instruction::POP, + Instruction::POP, + }); +} + BOOST_AUTO_TEST_SUITE_END() } -- cgit v1.2.3 From b3fc122845c9f986d13b2a6b52df686ab5f1818e Mon Sep 17 00:00:00 2001 From: chriseth Date: Thu, 26 Mar 2015 15:50:50 +0100 Subject: Optimizer for memory. --- SolidityOptimizer.cpp | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) (limited to 'SolidityOptimizer.cpp') diff --git a/SolidityOptimizer.cpp b/SolidityOptimizer.cpp index de4cac8f..cf35536e 100644 --- a/SolidityOptimizer.cpp +++ b/SolidityOptimizer.cpp @@ -444,6 +444,59 @@ BOOST_AUTO_TEST_CASE(cse_interleaved_storage_at_known_location_offset) }); } +BOOST_AUTO_TEST_CASE(cse_interleaved_memory_at_known_location_offset) +{ + // stores and reads to/from two locations which are known to be different, + // should not optimize away the first store, because the location overlaps with the load, + // but it should optimize away the second, because we know that the location is different by 32 + AssemblyItems input{ + u256(0x50), + Instruction::DUP2, + u256(2), + Instruction::ADD, + Instruction::MSTORE, // ["DUP1"+2] = 0x50 + u256(0x60), + Instruction::DUP2, + u256(32), + Instruction::ADD, + Instruction::MSTORE, // ["DUP1"+32] = 0x60 + Instruction::DUP1, + Instruction::MLOAD, // read from "DUP1" + u256(0x70), + Instruction::DUP3, + u256(32), + Instruction::ADD, + Instruction::MSTORE, // ["DUP1"+32] = 0x70 + u256(0x80), + Instruction::DUP3, + u256(2), + Instruction::ADD, + Instruction::MSTORE, // ["DUP1"+2] = 0x80 + }; + // If the actual code changes too much, we could also simply check that the output contains + // exactly 3 MSTORE and exactly 1 MLOAD instruction. + checkCSE(input, { + u256(0x50), + u256(2), + Instruction::DUP3, + Instruction::ADD, + Instruction::SWAP1, + Instruction::DUP2, + Instruction::MSTORE, // ["DUP1"+2] = 0x50 + Instruction::DUP2, + Instruction::MLOAD, // read from "DUP1" + u256(0x70), + u256(32), + Instruction::DUP5, + Instruction::ADD, + Instruction::MSTORE, // ["DUP1"+32] = 0x70 + u256(0x80), + Instruction::SWAP1, + Instruction::SWAP2, + Instruction::MSTORE // ["DUP1"+2] = 0x80 + }); +} + BOOST_AUTO_TEST_CASE(cse_deep_stack) { AssemblyItems input{ -- cgit v1.2.3 From 35274fb9b1a89589b60de7f54913d5f77712c6af Mon Sep 17 00:00:00 2001 From: chriseth Date: Fri, 27 Mar 2015 00:24:31 +0100 Subject: Optimize breaking item. --- SolidityOptimizer.cpp | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) (limited to 'SolidityOptimizer.cpp') diff --git a/SolidityOptimizer.cpp b/SolidityOptimizer.cpp index cf35536e..e69d5120 100644 --- a/SolidityOptimizer.cpp +++ b/SolidityOptimizer.cpp @@ -536,6 +536,38 @@ BOOST_AUTO_TEST_CASE(cse_deep_stack) }); } +BOOST_AUTO_TEST_CASE(cse_jumpi_no_jump) +{ + AssemblyItems input{ + u256(0), + u256(1), + Instruction::DUP2, + AssemblyItem(PushTag, 1), + Instruction::JUMPI + }; + checkCSE(input, { + u256(0), + u256(1) + }); +} + +BOOST_AUTO_TEST_CASE(cse_jumpi_jump) +{ + AssemblyItems input{ + u256(1), + u256(1), + Instruction::DUP2, + AssemblyItem(PushTag, 1), + Instruction::JUMPI + }; + checkCSE(input, { + u256(1), + Instruction::DUP1, + AssemblyItem(PushTag, 1), + Instruction::JUMP + }); +} + BOOST_AUTO_TEST_SUITE_END() } -- cgit v1.2.3