diff --git a/libyul/backends/evm/EVMCodeTransform.cpp b/libyul/backends/evm/EVMCodeTransform.cpp index e4ba54b2a..d5530c52a 100644 --- a/libyul/backends/evm/EVMCodeTransform.cpp +++ b/libyul/backends/evm/EVMCodeTransform.cpp @@ -182,16 +182,24 @@ void CodeTransform::operator()(VariableDeclaration const& _varDecl) else m_variablesScheduledForDeletion.insert(&var); } - else if (m_unusedStackSlots.empty()) - atTopOfStack = false; else { - auto slot = static_cast(*m_unusedStackSlots.begin()); - m_unusedStackSlots.erase(m_unusedStackSlots.begin()); - m_context->variableStackHeights[&var] = slot; - if (size_t heightDiff = variableHeightDiff(var, varName, true)) - m_assembly.appendInstruction(evmasm::swapInstruction(static_cast(heightDiff - 1))); - m_assembly.appendInstruction(evmasm::Instruction::POP); + bool foundUnusedSlot = false; + for (auto it = m_unusedStackSlots.begin(); it != m_unusedStackSlots.end(); ++it) + { + if (m_assembly.stackHeight() - *it > 17) + continue; + foundUnusedSlot = true; + auto slot = static_cast(*it); + m_unusedStackSlots.erase(it); + m_context->variableStackHeights[&var] = slot; + if (size_t heightDiff = variableHeightDiff(var, varName, true)) + m_assembly.appendInstruction(evmasm::swapInstruction(static_cast(heightDiff - 1))); + m_assembly.appendInstruction(evmasm::Instruction::POP); + break; + } + if (!foundUnusedSlot) + atTopOfStack = false; } } } @@ -404,7 +412,7 @@ void CodeTransform::operator()(FunctionDefinition const& _function) subTransform.deleteVariable(var); } - if (!m_allowStackOpt || _function.returnVariables.empty()) + if (!m_allowStackOpt) subTransform.setupReturnVariablesAndFunctionExit(); subTransform(_function.body); @@ -594,6 +602,7 @@ void CodeTransform::visitExpression(Expression const& _expression) void CodeTransform::setupReturnVariablesAndFunctionExit() { + yulAssert(isInsideFunction(), ""); yulAssert(!returnVariablesAndFunctionExitAreSetup(), ""); yulAssert(m_scope, ""); @@ -656,7 +665,8 @@ void CodeTransform::visitStatements(vector const& _statements) { freeUnusedVariables(); if ( - !m_delayedReturnVariables.empty() && + isInsideFunction() && + !returnVariablesAndFunctionExitAreSetup() && statementNeedsReturnVariableSetup(statement, m_delayedReturnVariables) ) setupReturnVariablesAndFunctionExit(); diff --git a/libyul/backends/evm/EVMCodeTransform.h b/libyul/backends/evm/EVMCodeTransform.h index a76638850..894a6d077 100644 --- a/libyul/backends/evm/EVMCodeTransform.h +++ b/libyul/backends/evm/EVMCodeTransform.h @@ -181,6 +181,10 @@ private: { return m_functionExitStackHeight.has_value(); } + bool isInsideFunction() const + { + return m_functionExitLabel.has_value(); + } AbstractAssembly& m_assembly; AsmAnalysisInfo& m_info; diff --git a/test/libyul/evmCodeTransform/stackReuse/function_argument_reuse_without_retparams.yul b/test/libyul/evmCodeTransform/stackReuse/function_argument_reuse_without_retparams.yul new file mode 100644 index 000000000..d1f6b5bdc --- /dev/null +++ b/test/libyul/evmCodeTransform/stackReuse/function_argument_reuse_without_retparams.yul @@ -0,0 +1,29 @@ +{ + function f(x, y) { + mstore(0x80, x) + if calldataload(0) { sstore(y, y) } + } +} +// ==== +// stackOptimization: true +// ---- +// PUSH1 0x17 +// JUMP +// JUMPDEST +// DUP1 +// PUSH1 0x80 +// MSTORE +// POP +// PUSH1 0x0 +// CALLDATALOAD +// ISZERO +// PUSH1 0x13 +// JUMPI +// DUP1 +// DUP2 +// SSTORE +// JUMPDEST +// POP +// JUMPDEST +// JUMP +// JUMPDEST