Implement subroutines for yul functions.

This commit is contained in:
chriseth
2020-07-14 18:29:37 +01:00
committed by Alex Beregszaszi
parent dca85a286d
commit cc04085b9e
22 changed files with 105 additions and 51 deletions
+4 -1
View File
@@ -573,7 +573,10 @@ bool AsmAnalyzer::validateInstructions(evmasm::Instruction _instr, SourceLocatio
yulAssert(
_instr != evmasm::Instruction::JUMP &&
_instr != evmasm::Instruction::JUMPI &&
_instr != evmasm::Instruction::JUMPDEST,
_instr != evmasm::Instruction::JUMPDEST &&
_instr != evmasm::Instruction::JUMPSUB &&
_instr != evmasm::Instruction::RETURNSUB &&
_instr != evmasm::Instruction::BEGINSUB
"");
auto errorForVM = [&](ErrorId _errorId, string const& vmKindMessage) {
+3
View File
@@ -70,6 +70,9 @@ std::map<string, evmasm::Instruction> const& Parser::instructions()
{
if (
instruction.second == evmasm::Instruction::JUMPDEST ||
instruction.second == evmasm::Instruction::BEGINSUB ||
instruction.second == evmasm::Instruction::JUMPSUB ||
instruction.second == evmasm::Instruction::RETURNSUB ||
evmasm::isPushInstruction(instruction.second)
)
continue;
+9 -9
View File
@@ -116,22 +116,22 @@ void EthAssemblyAdapter::appendJumpToIf(LabelID _labelId, JumpType _jumpType)
appendJumpInstruction(evmasm::Instruction::JUMPI, _jumpType);
}
void EthAssemblyAdapter::appendBeginsub(LabelID, int)
void EthAssemblyAdapter::appendBeginsub(LabelID _labelId, int)
{
// TODO we could emulate that, though
yulAssert(false, "BEGINSUB not implemented for EVM 1.0");
m_assembly.append(evmasm::AssemblyItem(evmasm::Subtag, _labelId));
}
void EthAssemblyAdapter::appendJumpsub(LabelID, int, int)
void EthAssemblyAdapter::appendJumpsub(LabelID _labelId, int _args, int _returns)
{
// TODO we could emulate that, though
yulAssert(false, "JUMPSUB not implemented for EVM 1.0");
appendLabelReference(_labelId);
appendInstruction(evmasm::Instruction::JUMPSUB);
m_assembly.adjustDeposit(-_args + _returns);
}
void EthAssemblyAdapter::appendReturnsub(int, int)
void EthAssemblyAdapter::appendReturnsub(int _returns, int _stackDiffAfter)
{
// TODO we could emulate that, though
yulAssert(false, "RETURNSUB not implemented for EVM 1.0");
appendInstruction(evmasm::Instruction::RETURNSUB);
m_assembly.adjustDeposit(_stackDiffAfter - _returns);
}
void EthAssemblyAdapter::appendAssemblySize()
+2 -2
View File
@@ -53,8 +53,8 @@ public:
void appendJumpTo(LabelID _labelId, int _stackDiffAfter, JumpType _jumpType) override;
void appendJumpToIf(LabelID _labelId, JumpType _jumpType) override;
void appendBeginsub(LabelID, int) override;
void appendJumpsub(LabelID, int, int) override;
void appendReturnsub(int, int) override;
void appendJumpsub(LabelID, int _args, int _returns) override;
void appendReturnsub(int _returns, int _stackDiffAfter) override;
void appendAssemblySize() override;
std::pair<std::shared_ptr<AbstractAssembly>, SubID> createSubAssembly() override;
void appendDataOffset(SubID _sub) override;
+7 -5
View File
@@ -267,7 +267,7 @@ void CodeTransform::operator()(FunctionCall const& _call)
{
m_assembly.setSourceLocation(_call.location);
EVMAssembly::LabelID returnLabel(numeric_limits<EVMAssembly::LabelID>::max()); // only used for evm 1.0
if (!m_evm15)
if (!m_evm15 && !m_dialect.evmVersion().supportsSubroutines())
{
returnLabel = m_assembly.newLabelId();
m_assembly.appendLabelReference(returnLabel);
@@ -283,7 +283,7 @@ void CodeTransform::operator()(FunctionCall const& _call)
for (auto const& arg: _call.arguments | boost::adaptors::reversed)
visitExpression(arg);
m_assembly.setSourceLocation(_call.location);
if (m_evm15)
if (m_evm15 || m_dialect.evmVersion().supportsSubroutines())
m_assembly.appendJumpsub(
functionEntryID(_call.functionName.name, *function),
static_cast<int>(function->arguments.size()),
@@ -417,7 +417,7 @@ void CodeTransform::operator()(FunctionDefinition const& _function)
m_assembly.setSourceLocation(_function.location);
int const stackHeightBefore = m_assembly.stackHeight();
if (m_evm15)
if (m_evm15 || m_dialect.evmVersion().supportsSubroutines())
m_assembly.appendBeginsub(functionEntryID(_function.name, function), static_cast<int>(_function.parameters.size()));
else
m_assembly.appendLabel(functionEntryID(_function.name, function));
@@ -475,7 +475,7 @@ void CodeTransform::operator()(FunctionDefinition const& _function)
// This vector holds the desired target positions of all stack slots and is
// modified parallel to the actual stack.
vector<int> stackLayout;
if (!m_evm15)
if (!m_evm15 && !m_dialect.evmVersion().supportsSubroutines())
stackLayout.push_back(static_cast<int>(_function.returnVariables.size())); // Move return label to the top
stackLayout += vector<int>(_function.parameters.size(), -1); // discard all arguments
@@ -511,7 +511,7 @@ void CodeTransform::operator()(FunctionDefinition const& _function)
yulAssert(i == static_cast<size_t>(stackLayout[i]), "Error reshuffling stack.");
}
}
if (m_evm15)
if (m_evm15 || m_dialect.evmVersion().supportsSubroutines())
m_assembly.appendReturnsub(static_cast<int>(_function.returnVariables.size()), stackHeightBefore);
else
m_assembly.appendJump(
@@ -519,6 +519,8 @@ void CodeTransform::operator()(FunctionDefinition const& _function)
AbstractAssembly::JumpType::OutOfFunction
);
m_assembly.setStackHeight(stackHeightBefore);
// TODO add BEGINSUB?
// We need to make sure that we did function hoister and move the "main code" to the beginning.
}
void CodeTransform::operator()(ForLoop const& _forLoop)
-4
View File
@@ -101,21 +101,17 @@ void NoOutputAssembly::appendJumpToIf(LabelID _labelId, JumpType)
void NoOutputAssembly::appendBeginsub(LabelID, int _arguments)
{
yulAssert(m_evm15, "BEGINSUB used for EVM 1.0");
yulAssert(_arguments >= 0, "");
m_stackHeight += _arguments;
}
void NoOutputAssembly::appendJumpsub(LabelID, int _arguments, int _returns)
{
yulAssert(m_evm15, "JUMPSUB used for EVM 1.0");
yulAssert(_arguments >= 0 && _returns >= 0, "");
m_stackHeight += _returns - _arguments;
}
void NoOutputAssembly::appendReturnsub(int _returns, int _stackDiffAfter)
{
yulAssert(m_evm15, "RETURNSUB used for EVM 1.0");
yulAssert(_returns >= 0, "");
m_stackHeight += _stackDiffAfter - _returns;
}