Have the stack optimization in the code transform only reuse slots that are reachable and fix argument slot reuse on functions without return variables.

This commit is contained in:
Daniel Kirchner 2021-04-13 22:25:13 +02:00 committed by hrkrshnn
parent dfce7b667d
commit bc288aacf5
3 changed files with 53 additions and 10 deletions

View File

@ -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<size_t>(*m_unusedStackSlots.begin());
m_unusedStackSlots.erase(m_unusedStackSlots.begin());
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<size_t>(*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<unsigned>(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<Statement> const& _statements)
{
freeUnusedVariables();
if (
!m_delayedReturnVariables.empty() &&
isInsideFunction() &&
!returnVariablesAndFunctionExitAreSetup() &&
statementNeedsReturnVariableSetup(statement, m_delayedReturnVariables)
)
setupReturnVariablesAndFunctionExit();

View File

@ -181,6 +181,10 @@ private:
{
return m_functionExitStackHeight.has_value();
}
bool isInsideFunction() const
{
return m_functionExitLabel.has_value();
}
AbstractAssembly& m_assembly;
AsmAnalysisInfo& m_info;

View File

@ -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