Restore old code path for disabled stack optimization.

This commit is contained in:
Daniel Kirchner 2021-03-09 17:43:45 +01:00
parent 2b7b78ce42
commit c08f087742
2 changed files with 61 additions and 3 deletions

View File

@ -528,7 +528,7 @@ void CodeTransform::operator()(FunctionDefinition const& _function)
);
stackError(std::move(error), static_cast<int>(_function.returnVariables.size()) + 1);
}
else
else if (m_allowStackOpt)
{
// This vector stores true for stack slots containing return labels or return values,
// false otherwise.
@ -573,6 +573,55 @@ void CodeTransform::operator()(FunctionDefinition const& _function)
// So we need an additional swap to completely order the return values and get the return label to the top.
m_assembly.appendInstruction(evmasm::swapInstruction(static_cast<unsigned>(_function.returnVariables.size())));
}
else
{
// The stack layout here is:
// <return label> <arguments...> <return values...>
// But we would like it to be:
// <return values...> <return label>
// So we have to append some SWAP and POP instructions.
// This vector holds the desired target positions of all stack slots and is
// modified parallel to the actual stack.
vector<int> stackLayout(static_cast<size_t>(m_assembly.stackHeight()), -1);
stackLayout[0] = static_cast<int>(_function.returnVariables.size()); // Move return label to the top
for (auto&& [n, returnVariable]: ranges::views::enumerate(_function.returnVariables))
stackLayout.at(m_context->variableStackHeights.at(
&std::get<Scope::Variable>(virtualFunctionScope->identifiers.at(returnVariable.name))
)) = static_cast<int>(n);
if (stackLayout.size() > 17)
{
StackTooDeepError error(
_function.name,
YulString{},
static_cast<int>(stackLayout.size()) - 17,
"The function " +
_function.name.str() +
" has " +
to_string(stackLayout.size() - 17) +
" parameters or return variables too many to fit the stack size."
);
stackError(std::move(error), m_assembly.stackHeight() - static_cast<int>(_function.parameters.size()));
}
else
{
while (!stackLayout.empty() && stackLayout.back() != static_cast<int>(stackLayout.size() - 1))
if (stackLayout.back() < 0)
{
m_assembly.appendInstruction(evmasm::Instruction::POP);
stackLayout.pop_back();
}
else
{
m_assembly.appendInstruction(evmasm::swapInstruction(static_cast<unsigned>(stackLayout.size()) - static_cast<unsigned>(stackLayout.back()) - 1u));
swap(stackLayout[static_cast<size_t>(stackLayout.back())], stackLayout.back());
}
for (size_t i = 0; i < stackLayout.size(); ++i)
yulAssert(i == static_cast<size_t>(stackLayout[i]), "Error reshuffling stack.");
}
}
m_assembly.appendJump(
stackHeightBefore - static_cast<int>(_function.returnVariables.size()),
AbstractAssembly::JumpType::OutOfFunction
@ -708,6 +757,15 @@ void CodeTransform::setupReturnVariablesAndFunctionExit()
return;
}
if (!m_allowStackOpt)
{
for (TypedName const& var: m_delayedReturnVariables)
(*this)(VariableDeclaration{var.location, {var}, {}});
m_functionExitStackHeight = m_assembly.stackHeight();
m_delayedReturnVariables.clear();
return;
}
int height = m_assembly.stackHeight();
// Determine the set of stack slots available for putting in return variables.

View File

@ -14,9 +14,9 @@ contract C {
}
// ----
// creation:
// codeDepositCost: 1167800
// codeDepositCost: 1170600
// executionCost: 1214
// totalCost: 1169014
// totalCost: 1171814
// external:
// a(): 1130
// b(uint256): infinite