diff --git a/libevmasm/CommonSubexpressionEliminator.cpp b/libevmasm/CommonSubexpressionEliminator.cpp index 2c4742d61..8fb4625a8 100644 --- a/libevmasm/CommonSubexpressionEliminator.cpp +++ b/libevmasm/CommonSubexpressionEliminator.cpp @@ -79,31 +79,43 @@ void CommonSubexpressionEliminator::feedItem(AssemblyItem const& _item, bool _co void CommonSubexpressionEliminator::optimizeBreakingItem() { - if (!m_breakingItem || *m_breakingItem != AssemblyItem(Instruction::JUMPI)) + if (!m_breakingItem) return; + ExpressionClasses& classes = m_state.expressionClasses(); SourceLocation const& location = m_breakingItem->getLocation(); - AssemblyItem::JumpType jumpType = m_breakingItem->getJumpType(); - - Id condition = m_state.stackElement(m_state.stackHeight() - 1, location); - Id zero = m_state.expressionClasses().find(u256(0)); - if (m_state.expressionClasses().knownToBeDifferent(condition, zero)) + if (*m_breakingItem == AssemblyItem(Instruction::JUMPI)) { - feedItem(AssemblyItem(Instruction::SWAP1, location), true); - feedItem(AssemblyItem(Instruction::POP, location), true); + AssemblyItem::JumpType jumpType = m_breakingItem->getJumpType(); - AssemblyItem item(Instruction::JUMP, location); - item.setJumpType(jumpType); - m_breakingItem = m_state.expressionClasses().storeItem(item); - return; + Id condition = m_state.stackElement(m_state.stackHeight() - 1, location); + if (classes.knownNonZero(condition)) + { + feedItem(AssemblyItem(Instruction::SWAP1, location), true); + feedItem(AssemblyItem(Instruction::POP, location), true); + + AssemblyItem item(Instruction::JUMP, location); + item.setJumpType(jumpType); + m_breakingItem = classes.storeItem(item); + } + else if (classes.knownZero(condition)) + { + AssemblyItem it(Instruction::POP, location); + feedItem(it, true); + feedItem(it, true); + m_breakingItem = nullptr; + } } - Id negatedCondition = m_state.expressionClasses().find(Instruction::ISZERO, {condition}); - if (m_state.expressionClasses().knownToBeDifferent(negatedCondition, zero)) + else if (*m_breakingItem == AssemblyItem(Instruction::RETURN)) { - AssemblyItem it(Instruction::POP, location); - feedItem(it, true); - feedItem(it, true); - m_breakingItem = nullptr; + Id size = m_state.stackElement(m_state.stackHeight() - 1, location); + if (classes.knownZero(size)) + { + feedItem(AssemblyItem(Instruction::POP, location), true); + feedItem(AssemblyItem(Instruction::POP, location), true); + AssemblyItem item(Instruction::STOP, location); + m_breakingItem = classes.storeItem(item); + } } } diff --git a/libsolidity/Compiler.cpp b/libsolidity/Compiler.cpp index 950b1e756..b2b8bfa4c 100644 --- a/libsolidity/Compiler.cpp +++ b/libsolidity/Compiler.cpp @@ -298,7 +298,10 @@ void Compiler::appendReturnValuePacker(TypePointers const& _typeParameters) stackDepth -= type->getSizeOnStack(); } // note that the stack is not cleaned up here - m_context << u256(dataOffset) << u256(0) << eth::Instruction::RETURN; + if (dataOffset == 0) + m_context << eth::Instruction::STOP; + else + m_context << u256(dataOffset) << u256(0) << eth::Instruction::RETURN; } void Compiler::registerStateVariables(ContractDefinition const& _contract) diff --git a/test/libsolidity/SolidityOptimizer.cpp b/test/libsolidity/SolidityOptimizer.cpp index 397ee6316..85a88c030 100644 --- a/test/libsolidity/SolidityOptimizer.cpp +++ b/test/libsolidity/SolidityOptimizer.cpp @@ -944,6 +944,14 @@ BOOST_AUTO_TEST_CASE(cse_access_previous_sequence) // 0, SLOAD, 1, ADD, SSTORE, 0 SLOAD } +BOOST_AUTO_TEST_CASE(cse_optimise_return) +{ + checkCSE( + AssemblyItems{u256(0), u256(7), Instruction::RETURN}, + AssemblyItems{Instruction::STOP} + ); +} + BOOST_AUTO_TEST_CASE(control_flow_graph_remove_unused) { // remove parts of the code that are unused