From 8416a6260f3545ae7109091a09bef9291db59179 Mon Sep 17 00:00:00 2001 From: chriseth Date: Wed, 29 Apr 2015 18:16:05 +0200 Subject: [PATCH 1/3] Split known state from common subexpression eliminator. --- libsolidity/SolidityOptimizer.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/libsolidity/SolidityOptimizer.cpp b/libsolidity/SolidityOptimizer.cpp index 9cdaa5886..71463f919 100644 --- a/libsolidity/SolidityOptimizer.cpp +++ b/libsolidity/SolidityOptimizer.cpp @@ -90,7 +90,8 @@ public: for (AssemblyItem& item: input) item.setLocation(SourceLocation(1, 3, make_shared(""))); - eth::CommonSubexpressionEliminator cse; + eth::KnownState state; + eth::CommonSubexpressionEliminator cse(state); BOOST_REQUIRE(cse.feedItems(input.begin(), input.end()) == input.end()); AssemblyItems output = cse.getOptimizedItems(); @@ -231,7 +232,8 @@ BOOST_AUTO_TEST_CASE(function_calls) BOOST_AUTO_TEST_CASE(cse_intermediate_swap) { - eth::CommonSubexpressionEliminator cse; + eth::KnownState state; + eth::CommonSubexpressionEliminator cse(state); AssemblyItems input{ Instruction::SWAP1, Instruction::POP, Instruction::ADD, u256(0), Instruction::SWAP1, Instruction::SLOAD, Instruction::SWAP1, u256(100), Instruction::EXP, Instruction::SWAP1, From 3649c1fc60bf64171f843ec1cb73697b9f0ebd3f Mon Sep 17 00:00:00 2001 From: chriseth Date: Thu, 30 Apr 2015 14:41:55 +0200 Subject: [PATCH 2/3] Common subexpression elimination ready for using pre-known state. --- libsolidity/SolidityOptimizer.cpp | 49 ++++++++++++++++++++++++++++--- 1 file changed, 45 insertions(+), 4 deletions(-) diff --git a/libsolidity/SolidityOptimizer.cpp b/libsolidity/SolidityOptimizer.cpp index 71463f919..59e8f04a8 100644 --- a/libsolidity/SolidityOptimizer.cpp +++ b/libsolidity/SolidityOptimizer.cpp @@ -83,15 +83,28 @@ public: "\nOptimized: " + toHex(optimizedOutput)); } - AssemblyItems getCSE(AssemblyItems const& _input) + AssemblyItems addDummyLocations(AssemblyItems const& _input) { // add dummy locations to each item so that we can check that they are not deleted AssemblyItems input = _input; for (AssemblyItem& item: input) item.setLocation(SourceLocation(1, 3, make_shared(""))); + return input; + } + eth::KnownState createInitialState(AssemblyItems const& _input) + { eth::KnownState state; - eth::CommonSubexpressionEliminator cse(state); + for (auto const& item: addDummyLocations(_input)) + state.feedItem(item); + return state; + } + + AssemblyItems getCSE(AssemblyItems const& _input, eth::KnownState const& _state = eth::KnownState()) + { + AssemblyItems input = addDummyLocations(_input); + + eth::CommonSubexpressionEliminator cse(_state); BOOST_REQUIRE(cse.feedItems(input.begin(), input.end()) == input.end()); AssemblyItems output = cse.getOptimizedItems(); @@ -102,9 +115,13 @@ public: return output; } - void checkCSE(AssemblyItems const& _input, AssemblyItems const& _expectation) + void checkCSE( + AssemblyItems const& _input, + AssemblyItems const& _expectation, + KnownState const& _state = eth::KnownState() + ) { - AssemblyItems output = getCSE(_input); + AssemblyItems output = getCSE(_input, _state); BOOST_CHECK_EQUAL_COLLECTIONS(_expectation.begin(), _expectation.end(), output.begin(), output.end()); } @@ -756,6 +773,30 @@ BOOST_AUTO_TEST_CASE(cse_sha3_twice_same_content_noninterfering_store_in_between BOOST_CHECK_EQUAL(1, count(output.begin(), output.end(), AssemblyItem(Instruction::SHA3))); } +BOOST_AUTO_TEST_CASE(cse_with_initially_known_stack) +{ + eth::KnownState state = createInitialState(AssemblyItems{ + u256(0x12), + u256(0x20), + Instruction::ADD + }); + AssemblyItems input{ + u256(0x12 + 0x20) + }; + checkCSE(input, AssemblyItems{Instruction::DUP1}, state); +} + +BOOST_AUTO_TEST_CASE(cse_equality_on_initially_known_stack) +{ + eth::KnownState state = createInitialState(AssemblyItems{Instruction::DUP1}); + AssemblyItems input{ + Instruction::EQ + }; + AssemblyItems output = getCSE(input, state); + // check that it directly pushes 1 (true) + BOOST_CHECK(find(output.begin(), output.end(), AssemblyItem(u256(1))) != output.end()); +} + BOOST_AUTO_TEST_CASE(control_flow_graph_remove_unused) { // remove parts of the code that are unused From a0cc8abb2a162f883b5afd4757f52d926cf6df0b Mon Sep 17 00:00:00 2001 From: chriseth Date: Tue, 5 May 2015 17:45:58 +0200 Subject: [PATCH 3/3] CFG returns vector of blocks instead of assembly items. --- libsolidity/SolidityOptimizer.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/libsolidity/SolidityOptimizer.cpp b/libsolidity/SolidityOptimizer.cpp index 59e8f04a8..3cb6a536a 100644 --- a/libsolidity/SolidityOptimizer.cpp +++ b/libsolidity/SolidityOptimizer.cpp @@ -131,8 +131,12 @@ public: // Running it four times should be enough for these tests. for (unsigned i = 0; i < 4; ++i) { - eth::ControlFlowGraph cfg(output); - output = cfg.optimisedItems(); + ControlFlowGraph cfg(output); + AssemblyItems optItems; + for (BasicBlock const& block: cfg.optimisedBlocks()) + copy(output.begin() + block.begin, output.begin() + block.end, + back_inserter(optItems)); + output = move(optItems); } BOOST_CHECK_EQUAL_COLLECTIONS(_expectation.begin(), _expectation.end(), output.begin(), output.end()); }