diff --git a/libyul/CMakeLists.txt b/libyul/CMakeLists.txt
index e512a1b9b..6cfd7f988 100644
--- a/libyul/CMakeLists.txt
+++ b/libyul/CMakeLists.txt
@@ -71,6 +71,8 @@ add_library(yul
backends/evm/EVMObjectCompiler.h
backends/evm/EVMMetrics.cpp
backends/evm/EVMMetrics.h
+ backends/evm/DirectEVMCodeTransform.cpp
+ backends/evm/DirectEVMCodeTransform.h
backends/evm/DirectStackLayoutGenerator.cpp
backends/evm/DirectStackLayoutGenerator.h
backends/evm/NoOutputAssembly.h
diff --git a/libyul/backends/evm/DirectEVMCodeTransform.cpp b/libyul/backends/evm/DirectEVMCodeTransform.cpp
new file mode 100644
index 000000000..3e9b7f8f2
--- /dev/null
+++ b/libyul/backends/evm/DirectEVMCodeTransform.cpp
@@ -0,0 +1,233 @@
+/*
+ This file is part of solidity.
+
+ solidity is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ solidity is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with solidity. If not, see .
+*/
+// SPDX-License-Identifier: GPL-3.0
+#include
+
+#include
+
+#include
+
+#include
+
+using namespace solidity;
+using namespace solidity::yul;
+using namespace std;
+
+void DirectEVMCodeTransform::run(
+ AbstractAssembly& _assembly,
+ BuiltinContext& _builtinContext,
+ UseNamedLabels _useNamedLabelsForFunctions,
+ AsmAnalysisInfo const& _analysisInfo,
+ Dialect const& _dialect,
+ Block const& _ast
+)
+{
+ DirectStackLayoutGenerator::Context context = DirectStackLayoutGenerator::run(_analysisInfo, _dialect, _ast);
+ DirectEVMCodeTransform codeTransform{
+ _assembly,
+ _builtinContext,
+ _useNamedLabelsForFunctions,
+ context,
+ _analysisInfo,
+ _dialect
+ };
+ codeTransform(_ast);
+}
+
+void DirectEVMCodeTransform::operator()(Block const& _block)
+{
+ auto const& blockInfo = m_context.layout.blockInfos.at(&_block);
+ createStackLayout(debugDataOf(_block), blockInfo.entry);
+ for(auto const& _statement: _block.statements)
+ {
+ auto const& statementInfo = m_context.layout.statementInfos.at(&_statement);
+ createStackLayout(debugDataOf(_statement), statementInfo);
+ visit(_statement);
+ }
+}
+
+void DirectEVMCodeTransform::operator()(FunctionCall const&)
+{
+
+}
+void DirectEVMCodeTransform::operator()(ExpressionStatement const&)
+{
+
+}
+void DirectEVMCodeTransform::operator()(Assignment const&)
+{
+
+}
+void DirectEVMCodeTransform::operator()(VariableDeclaration const&)
+{
+
+}
+void DirectEVMCodeTransform::operator()(If const&)
+{
+ yulAssert(false, "");
+}
+void DirectEVMCodeTransform::operator()(Switch const&)
+{
+ yulAssert(false, "");
+}
+void DirectEVMCodeTransform::operator()(ForLoop const&)
+{
+ yulAssert(false, "");
+}
+void DirectEVMCodeTransform::operator()(FunctionDefinition const&)
+{
+
+}
+void DirectEVMCodeTransform::operator()(Break const&)
+{
+ yulAssert(false, "");
+}
+void DirectEVMCodeTransform::operator()(Continue const&)
+{
+ yulAssert(false, "");
+}
+void DirectEVMCodeTransform::operator()(Leave const&)
+{
+ yulAssert(false, "");
+}
+
+
+void DirectEVMCodeTransform::createStackLayout(std::shared_ptr _debugData, Stack _targetStack)
+{
+ static constexpr auto slotVariableName = [](StackSlot const& _slot) {
+ return std::visit(util::GenericVisitor{
+ [](VariableSlot const& _var) { return _var.variable.get().name; },
+ [](auto const&) { return YulString{}; }
+ }, _slot);
+ };
+
+ yulAssert(m_assembly.stackHeight() == static_cast(m_stack.size()), "");
+ // ::createStackLayout asserts that it has successfully achieved the target layout.
+ langutil::SourceLocation sourceLocation = _debugData ? _debugData->originLocation : langutil::SourceLocation{};
+ m_assembly.setSourceLocation(sourceLocation);
+ ::createStackLayout(
+ m_stack,
+ _targetStack | ranges::to,
+ // Swap callback.
+ [&](unsigned _i)
+ {
+ yulAssert(static_cast(m_stack.size()) == m_assembly.stackHeight(), "");
+ yulAssert(_i > 0 && _i < m_stack.size(), "");
+ if (_i <= 16)
+ m_assembly.appendInstruction(evmasm::swapInstruction(_i));
+ else
+ {
+ int deficit = static_cast(_i) - 16;
+ StackSlot const& deepSlot = m_stack.at(m_stack.size() - _i - 1);
+ YulString varNameDeep = slotVariableName(deepSlot);
+ YulString varNameTop = slotVariableName(m_stack.back());
+ string msg =
+ "Cannot swap " + (varNameDeep.empty() ? "Slot " + stackSlotToString(deepSlot) : "Variable " + varNameDeep.str()) +
+ " with " + (varNameTop.empty() ? "Slot " + stackSlotToString(m_stack.back()) : "Variable " + varNameTop.str()) +
+ ": too deep in the stack by " + to_string(deficit) + " slots in " + stackToString(m_stack);
+ m_stackErrors.emplace_back(StackTooDeepError(
+ m_currentFunctionInfo ? m_currentFunctionInfo->function.name : YulString{},
+ varNameDeep.empty() ? varNameTop : varNameDeep,
+ deficit,
+ msg
+ ));
+ m_assembly.markAsInvalid();
+ }
+ },
+ // Push or dup callback.
+ [&](StackSlot const& _slot)
+ {
+ yulAssert(static_cast(m_stack.size()) == m_assembly.stackHeight(), "");
+
+ // Dup the slot, if already on stack and reachable.
+ if (auto depth = util::findOffset(m_stack | ranges::views::reverse, _slot))
+ {
+ if (*depth < 16)
+ {
+ m_assembly.appendInstruction(evmasm::dupInstruction(static_cast(*depth + 1)));
+ return;
+ }
+ else if (!canBeFreelyGenerated(_slot))
+ {
+ int deficit = static_cast(*depth - 15);
+ YulString varName = slotVariableName(_slot);
+ string msg =
+ (varName.empty() ? "Slot " + stackSlotToString(_slot) : "Variable " + varName.str())
+ + " is " + to_string(*depth - 15) + " too deep in the stack " + stackToString(m_stack);
+ m_stackErrors.emplace_back(StackTooDeepError(
+ m_currentFunctionInfo ? m_currentFunctionInfo->function.name : YulString{},
+ varName,
+ deficit,
+ msg
+ ));
+ m_assembly.markAsInvalid();
+ m_assembly.appendConstant(u256(0xCAFFEE));
+ return;
+ }
+ // else: the slot is too deep in stack, but can be freely generated, we fall through to push it again.
+ }
+
+ // The slot can be freely generated or is an unassigned return variable. Push it.
+ std::visit(util::GenericVisitor{
+ [&](LiteralSlot const& _literal)
+ {
+ m_assembly.setSourceLocation(originLocationOf(_literal));
+ m_assembly.appendConstant(_literal.value);
+ m_assembly.setSourceLocation(sourceLocation);
+ },
+ [&](FunctionReturnLabelSlot const&)
+ {
+ yulAssert(false, "Cannot produce function return label.");
+ },
+ [&](FunctionCallReturnLabelSlot const& _returnLabel)
+ {
+ if (!m_returnLabels.count(&_returnLabel.call.get()))
+ m_returnLabels[&_returnLabel.call.get()] = m_assembly.newLabelId();
+ m_assembly.setSourceLocation(originLocationOf(_returnLabel.call.get()));
+ m_assembly.appendLabelReference(m_returnLabels.at(&_returnLabel.call.get()));
+ m_assembly.setSourceLocation(sourceLocation);
+ },
+ [&](VariableSlot const& _variable)
+ {
+ if (m_currentFunctionInfo && util::contains(m_currentFunctionInfo->returnVariables, _variable))
+ {
+ m_assembly.setSourceLocation(originLocationOf(_variable));
+ m_assembly.appendConstant(0);
+ m_assembly.setSourceLocation(sourceLocation);
+ return;
+ }
+ yulAssert(false, "Variable not found on stack.");
+ },
+ [&](TemporarySlot const&)
+ {
+ yulAssert(false, "Function call result requested, but not found on stack.");
+ },
+ [&](JunkSlot const&)
+ {
+ // Note: this will always be popped, so we can push anything.
+ m_assembly.appendInstruction(evmasm::Instruction::CODESIZE);
+ }
+ }, _slot);
+ },
+ // Pop callback.
+ [&]()
+ {
+ m_assembly.appendInstruction(evmasm::Instruction::POP);
+ }
+ );
+ yulAssert(m_assembly.stackHeight() == static_cast(m_stack.size()), "");
+}
diff --git a/libyul/backends/evm/DirectEVMCodeTransform.h b/libyul/backends/evm/DirectEVMCodeTransform.h
new file mode 100644
index 000000000..cf25033f6
--- /dev/null
+++ b/libyul/backends/evm/DirectEVMCodeTransform.h
@@ -0,0 +1,98 @@
+/*
+ This file is part of solidity.
+
+ solidity is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ solidity is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with solidity. If not, see .
+*/
+// SPDX-License-Identifier: GPL-3.0
+/**
+ * Code generator for translating Yul / inline assembly to EVM.
+ */
+#pragma once
+
+#include
+#include
+#include
+
+namespace solidity::yul
+{
+
+class DirectEVMCodeTransform: public ASTWalker
+{
+public:
+ /// Use named labels for functions 1) Yes and check that the names are unique
+ /// 2) For none of the functions 3) for the first function of each name.
+ enum class UseNamedLabels { YesAndForceUnique, Never, ForFirstFunctionOfEachName };
+
+ static void run(
+ AbstractAssembly& _assembly,
+ BuiltinContext& _builtinContext,
+ UseNamedLabels _useNamedLabelsForFunctions,
+ AsmAnalysisInfo const& _analysisInfo,
+ Dialect const& _dialect,
+ Block const& _ast
+ );
+
+ void operator()(Literal const&) override;
+ void operator()(Identifier const&) override;
+ void operator()(FunctionCall const& _funCall) override;
+ void operator()(ExpressionStatement const& _statement) override;
+ void operator()(Assignment const& _assignment) override;
+ void operator()(VariableDeclaration const& _varDecl) override;
+ void operator()(If const& _if) override;
+ void operator()(Switch const& _switch) override;
+ void operator()(ForLoop const&) override;
+ void operator()(FunctionDefinition const&) override;
+ void operator()(Break const&) override;
+ void operator()(Continue const&) override;
+ void operator()(Leave const&) override;
+ void operator()(Block const& _block) override;
+
+ void visit(Statement const& _stmt) override;
+ using ASTWalker::visit;
+private:
+ DirectEVMCodeTransform(
+ AbstractAssembly& _assembly,
+ BuiltinContext& _builtinContext,
+ UseNamedLabels _useNamedLabelsForFunctions,
+ DirectStackLayoutGenerator::Context const& _context,
+ AsmAnalysisInfo const& _analysisInfo,
+ Dialect const& _dialect
+ ):
+ m_assembly(_assembly),
+ m_builtinContext(_builtinContext),
+ m_useNamedLabelsForFunctions(_useNamedLabelsForFunctions),
+ m_context(_context),
+ m_info(_analysisInfo),
+ m_dialect(_dialect)
+ {}
+
+ /// Shuffles m_stack to the desired @a _targetStack while emitting the shuffling code to m_assembly.
+ /// Sets the source locations to the one in @a _debugData.
+ void createStackLayout(std::shared_ptr _debugData, Stack _targetStack);
+
+ AbstractAssembly& m_assembly;
+ BuiltinContext& m_builtinContext;
+ UseNamedLabels m_useNamedLabelsForFunctions;
+ DirectStackLayoutGenerator::Context const& m_context;
+ AsmAnalysisInfo const& m_info;
+ Dialect const& m_dialect;
+ Stack m_stack;
+ CFG::FunctionInfo const* m_currentFunctionInfo = nullptr;
+ std::map m_returnLabels;
+ std::map m_blockLabels;
+ std::map const m_functionLabels;
+ std::vector m_stackErrors;
+};
+
+}
\ No newline at end of file
diff --git a/libyul/backends/evm/DirectStackLayoutGenerator.cpp b/libyul/backends/evm/DirectStackLayoutGenerator.cpp
index 7a84dd2d6..e923e8588 100644
--- a/libyul/backends/evm/DirectStackLayoutGenerator.cpp
+++ b/libyul/backends/evm/DirectStackLayoutGenerator.cpp
@@ -22,63 +22,266 @@
#include
#include
+#include
+
+#include
+#include
#include
+#include
#include
+#include
using namespace solidity;
using namespace solidity::yul;
using namespace std;
-void DirectStackLayoutGenerator::run(Block const& _block)
+DirectStackLayoutGenerator::Context DirectStackLayoutGenerator::run(AsmAnalysisInfo const& _analysisInfo, Dialect const& _dialect, Block const& _block)
{
+ /*
yulAssert(_block.statements.size() > 0, "");
yulAssert(holds_alternative(_block.statements.front()), "");
{
- DirectStackLayoutGenerator generator;
+ DirectStackLayoutGenerator generator{_analysisInfo, _dialect};
generator(get(_block.statements.front()));
}
for (Statement const& statement: _block.statements | ranges::views::drop_exactly(1))
{
FunctionDefinition const* functionDefinition = get_if(&statement);
yulAssert(functionDefinition, "");
- DirectStackLayoutGenerator generator;
+ DirectStackLayoutGenerator generator{_analysisInfo, _dialect};
generator(*functionDefinition);
- }
+ }*/
+ Context context;
+ DirectStackLayoutGenerator generator{context, _analysisInfo, _dialect};
+ generator(_block);
+ return context;
}
void DirectStackLayoutGenerator::operator()(Block const& _block)
{
+ ScopedSaveAndRestore saveScope(m_scope, m_info.scopes.at(&_block).get());
+ for (auto const& statement: _block.statements)
+ if (auto const* function = get_if(&statement))
+ registerFunction(*function);
for (Statement const& statement: _block.statements | ranges::views::reverse)
visit(statement);
+
+ m_context.layout.blockInfos[&_block].entry = m_stack;
}
void DirectStackLayoutGenerator::operator()(VariableDeclaration const& _variableDeclaration)
{
+ auto declaredVariables = _variableDeclaration.variables | ranges::views::transform([&](TypedName const& _var) {
+ return VariableSlot{lookupVariable(_var.name), _var.debugData};
+ }) | ranges::to>;
+ visitAssignmentOrDeclaration(
+ debugDataOf(_variableDeclaration),
+ declaredVariables,
+ _variableDeclaration.value ? _variableDeclaration.value.get() : nullptr
+ );
}
void DirectStackLayoutGenerator::operator()(Assignment const& _assignment)
{
+ auto assignedVariables = _assignment.variableNames | ranges::views::transform([&](Identifier const& _var) {
+ return VariableSlot{lookupVariable(_var.name), _var.debugData};
+ }) | ranges::to>;
+ visitAssignmentOrDeclaration(
+ debugDataOf(_assignment),
+ assignedVariables,
+ _assignment.value.get()
+ );
+}
+void DirectStackLayoutGenerator::operator()(Literal const& _literal)
+{
+ m_stack.emplace_back(LiteralSlot{valueOfLiteral(_literal), debugDataOf(_literal)});
+}
+
+void DirectStackLayoutGenerator::operator()(Identifier const& _identifier)
+{
+ m_stack.emplace_back(VariableSlot{lookupVariable(_identifier.name), debugDataOf(_identifier)});
+}
+
+void DirectStackLayoutGenerator::operator()(FunctionCall const& _funCall)
+{
+ yulAssert(visitFunctionCall(_funCall) == 1, "");
}
void DirectStackLayoutGenerator::operator()(ExpressionStatement const& _expressionStatement)
{
-
+ std::visit(util::GenericVisitor{
+ [&](FunctionCall const& _call) {
+ yulAssert(visitFunctionCall(_call) == 0, "");
+ },
+ [&](auto const&) { yulAssert(false, ""); }
+ }, _expressionStatement.expression);
}
void DirectStackLayoutGenerator::operator()(If const& _if)
{
+ DirectStackLayoutGenerator bodyGenerator{m_context, m_info, m_dialect, m_stack};
+ bodyGenerator(_if.body);
+ m_stack += move(bodyGenerator.m_stack);
+ visit(*_if.condition);
}
void DirectStackLayoutGenerator::operator()(Switch const& _switch)
{
+ Stack combinedStack;
+ for (auto const& switchCase: _switch.cases)
+ {
+ DirectStackLayoutGenerator bodyGenerator{m_context, m_info, m_dialect, m_stack};
+ bodyGenerator(switchCase.body);
+ for (auto const& slot: bodyGenerator.m_stack)
+ if (!util::contains(combinedStack, slot))
+ combinedStack.emplace_back(slot);
+ }
+ m_stack += move(combinedStack);
+ visit(*_switch.expression);
}
void DirectStackLayoutGenerator::operator()(ForLoop const& _forLoop)
{
+ yulAssert(_forLoop.pre.statements.empty(), "");
+ DirectStackLayoutGenerator bodyGenerator{m_context, m_info, m_dialect, m_stack};
+ bodyGenerator(_forLoop.post);
+ bodyGenerator(_forLoop.body);
+ m_stack += move(bodyGenerator.m_stack);
+ visit(*_forLoop.condition);
}
-void DirectStackLayoutGenerator::operator()(FunctionDefinition const& _functionDefinition)
+void DirectStackLayoutGenerator::operator()(FunctionDefinition const& _function)
{
-}
\ No newline at end of file
+ yulAssert(m_scope, "");
+ yulAssert(m_scope->identifiers.count(_function.name), "");
+ Scope::Function& function = std::get(m_scope->identifiers.at(_function.name));
+
+ auto const& functionInfo = m_context.functionInfo.at(&function);
+
+ yulAssert(m_info.scopes.at(&_function.body), "");
+ Scope* virtualFunctionScope = m_info.scopes.at(m_info.virtualBlocks.at(&_function).get()).get();
+ yulAssert(virtualFunctionScope, "");
+
+ DirectStackLayoutGenerator bodyGenerator{m_context, m_info, m_dialect, m_stack};
+ bodyGenerator.m_stack = functionInfo.returnVariables | ranges::views::transform([](auto const& _varSlot){
+ return StackSlot{_varSlot};
+ }) | ranges::to;
+ bodyGenerator.m_stack.emplace_back(FunctionReturnLabelSlot{function});
+ bodyGenerator(_function.body);
+}
+
+void DirectStackLayoutGenerator::visit(Statement const& _statement)
+{
+ ASTWalker::visit(_statement);
+ m_context.layout.statementInfos[&_statement] = m_stack;
+}
+
+size_t DirectStackLayoutGenerator::visitFunctionCall(FunctionCall const& _call)
+{
+ if (BuiltinFunction const* builtin = m_dialect.builtin(_call.functionName.name))
+ {
+ for (auto&& [idx, arg]: _call.arguments | ranges::views::enumerate | ranges::views::reverse)
+ if (!builtin->literalArgument(idx).has_value())
+ std::visit(*this, arg);
+ return builtin->returns.size();
+ }
+ else
+ {
+ m_stack.emplace_back(FunctionCallReturnLabelSlot{_call});
+ for (auto const& arg: _call.arguments | ranges::views::reverse)
+ std::visit(*this, arg);
+ Scope::Function const& function = lookupFunction(_call.functionName.name);
+ return function.returns.size();
+ }
+}
+
+void DirectStackLayoutGenerator::visitAssignmentOrDeclaration(
+ std::shared_ptr _debugData,
+ vector const& _variables,
+ Expression const* _expression
+)
+{
+ // TODO: reproduce proper createIdealLayout here
+ cxx20::erase_if(m_stack, [&](StackSlot const& slot) {
+ if (auto const* varSlot = get_if(&slot))
+ if (util::contains(_variables, *varSlot))
+ return true;
+ return false;
+ });
+ if (!_expression)
+ {
+ m_stack += Stack(_variables.size(), LiteralSlot{0, _debugData});
+ return;
+ }
+
+ if (_variables.size() == 1 && !holds_alternative(*_expression))
+ {
+ visit(*_expression);
+ return;
+ }
+
+ auto const* call = get_if(_expression);
+ yulAssert(call, "");
+ yulAssert(visitFunctionCall(*call) == _variables.size(), "");
+}
+
+Scope::Function const& DirectStackLayoutGenerator::lookupFunction(YulString _name) const
+{
+ Scope::Function const* function = nullptr;
+ yulAssert(m_scope->lookup(_name, util::GenericVisitor{
+ [](Scope::Variable&) { yulAssert(false, "Expected function name."); },
+ [&](Scope::Function& _function) { function = &_function; }
+ }), "Function name not found.");
+ yulAssert(function, "");
+ return *function;
+}
+
+Scope::Variable const& DirectStackLayoutGenerator::lookupVariable(YulString _name) const
+{
+ yulAssert(m_scope, "");
+ Scope::Variable const* var = nullptr;
+ if (m_scope->lookup(_name, util::GenericVisitor{
+ [&](Scope::Variable& _var) { var = &_var; },
+ [](Scope::Function&)
+ {
+ yulAssert(false, "Function not removed during desugaring.");
+ }
+ }))
+ {
+ yulAssert(var, "");
+ return *var;
+ };
+ yulAssert(false, "External identifier access unimplemented.");
+}
+
+void DirectStackLayoutGenerator::registerFunction(FunctionDefinition const& _function)
+{
+ yulAssert(m_scope, "");
+ yulAssert(m_scope->identifiers.count(_function.name), "");
+ Scope::Function& function = std::get(m_scope->identifiers.at(_function.name));
+ m_context.functionList.emplace_back(&function);
+
+ yulAssert(m_info.scopes.at(&_function.body), "");
+ Scope* virtualFunctionScope = m_info.scopes.at(m_info.virtualBlocks.at(&_function).get()).get();
+ yulAssert(virtualFunctionScope, "");
+
+ bool inserted = m_context.functionInfo.emplace(std::make_pair(&function, FunctionInfo{
+ _function.debugData,
+ function,
+ _function.parameters | ranges::views::transform([&](auto const& _param) {
+ return VariableSlot{
+ std::get(virtualFunctionScope->identifiers.at(_param.name)),
+ _param.debugData
+ };
+ }) | ranges::to,
+ _function.returnVariables | ranges::views::transform([&](auto const& _retVar) {
+ return VariableSlot{
+ std::get(virtualFunctionScope->identifiers.at(_retVar.name)),
+ _retVar.debugData
+ };
+ }) | ranges::to
+ })).second;
+ yulAssert(inserted);
+}
diff --git a/libyul/backends/evm/DirectStackLayoutGenerator.h b/libyul/backends/evm/DirectStackLayoutGenerator.h
index 352051e66..b0f8ea508 100644
--- a/libyul/backends/evm/DirectStackLayoutGenerator.h
+++ b/libyul/backends/evm/DirectStackLayoutGenerator.h
@@ -25,42 +25,75 @@
#include
+#include
+
namespace solidity::yul
{
struct StackLayout
{
- struct StackInfo
+ struct BlockInfo
{
Stack entry;
- Stack exit;
};
- std::map blockInfos;
- std::map statementInfos;
+ std::map blockInfos;
+ std::map statementInfos;
};
class DirectStackLayoutGenerator: public ASTWalker
{
public:
- static void run(Block const& _ast);
+ struct FunctionInfo {
+ std::shared_ptr debugData;
+ Scope::Function const& function;
+ std::vector parameters;
+ std::vector returnVariables;
+ };
+ struct Context {
+ StackLayout layout;
+ std::vector functionList;
+ std::map functionInfo;
+ };
+ static Context run(AsmAnalysisInfo const& _analysisInfo, Dialect const& _dialect, Block const& _ast);
+
+ void operator()(Literal const&) override;
+ void operator()(Identifier const&) override;
+ void operator()(FunctionCall const& _funCall) override;
+ void operator()(ExpressionStatement const& _statement) override;
+ void operator()(Assignment const& _assignment) override;
+ void operator()(VariableDeclaration const& _varDecl) override;
+ void operator()(If const& _if) override;
+ void operator()(Switch const& _switch) override;
+ void operator()(ForLoop const&) override;
+ void operator()(FunctionDefinition const&) override;
+ void operator()(Break const&) override;
+ void operator()(Continue const&) override;
+ void operator()(Leave const&) override;
+ void operator()(Block const& _block) override;
+
+ void visit(Statement const& _stmt) override;
+ using ASTWalker::visit;
- virtual void operator()(Literal const&) {}
- virtual void operator()(Identifier const&) {}
- virtual void operator()(FunctionCall const& _funCall);
- virtual void operator()(ExpressionStatement const& _statement);
- virtual void operator()(Assignment const& _assignment);
- virtual void operator()(VariableDeclaration const& _varDecl);
- virtual void operator()(If const& _if);
- virtual void operator()(Switch const& _switch);
- virtual void operator()(ForLoop const&);
- virtual void operator()(FunctionDefinition const&);
- virtual void operator()(Break const&);
- virtual void operator()(Continue const&);
- virtual void operator()(Leave const&);
- virtual void operator()(Block const& _block);
private:
- DirectStackLayoutGenerator() {}
+ DirectStackLayoutGenerator(Context& _context, AsmAnalysisInfo const& _info, Dialect const& _dialect, Stack _prefix = {}):
+ m_context(_context), m_info(_info), m_dialect(_dialect), m_prefix(std::move(_prefix)) {}
+
+ size_t visitFunctionCall(FunctionCall const&);
+ void visitAssignmentOrDeclaration(
+ std::shared_ptr _debugData,
+ std::vector const& _variables,
+ Expression const* _expression
+ );
+ Scope::Function const& lookupFunction(YulString _name) const;
+ Scope::Variable const& lookupVariable(YulString _name) const;
+ void registerFunction(FunctionDefinition const& _function);
+
+ Context& m_context;
+ AsmAnalysisInfo const& m_info;
+ Dialect const& m_dialect;
+ Scope* m_scope = nullptr;
+ Stack m_prefix;
Stack m_stack;
};