mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Add IRVariable
This commit is contained in:
parent
0819e31de8
commit
1a8e9f6ac4
@ -204,6 +204,8 @@ set(sources
|
|||||||
experimental/ast/TypeSystemHelper.h
|
experimental/ast/TypeSystemHelper.h
|
||||||
experimental/codegen/Common.h
|
experimental/codegen/Common.h
|
||||||
experimental/codegen/Common.cpp
|
experimental/codegen/Common.cpp
|
||||||
|
experimental/codegen/IRVariable.cpp
|
||||||
|
experimental/codegen/IRVariable.h
|
||||||
experimental/codegen/IRGenerationContext.h
|
experimental/codegen/IRGenerationContext.h
|
||||||
experimental/codegen/IRGenerator.cpp
|
experimental/codegen/IRGenerator.cpp
|
||||||
experimental/codegen/IRGenerator.h
|
experimental/codegen/IRGenerator.h
|
||||||
|
@ -101,7 +101,7 @@ private:
|
|||||||
auto type = m_context.analysis.annotation<TypeInference>(*varDecl).type;
|
auto type = m_context.analysis.annotation<TypeInference>(*varDecl).type;
|
||||||
solAssert(type);
|
solAssert(type);
|
||||||
solAssert(m_context.env->typeEquals(*type, m_context.analysis.typeSystem().type(PrimitiveType::Word, {})));
|
solAssert(m_context.env->typeEquals(*type, m_context.analysis.typeSystem().type(PrimitiveType::Word, {})));
|
||||||
std::string value = IRNames::localVariable(*varDecl);
|
std::string value = IRVariable{*varDecl, *type}.name();
|
||||||
return yul::Identifier{_identifier.debugData, yul::YulString{value}};
|
return yul::Identifier{_identifier.debugData, yul::YulString{value}};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -119,7 +119,7 @@ bool IRGeneratorForStatements::visit(TupleExpression const& _tupleExpression)
|
|||||||
{
|
{
|
||||||
solUnimplementedAssert(component);
|
solUnimplementedAssert(component);
|
||||||
component->accept(*this);
|
component->accept(*this);
|
||||||
components.emplace_back(IRNames::localVariable(*component));
|
components.emplace_back(IRVariable{*component, type(*component)}.name());
|
||||||
}
|
}
|
||||||
|
|
||||||
solUnimplementedAssert(false, "No support for tuples.");
|
solUnimplementedAssert(false, "No support for tuples.");
|
||||||
@ -144,9 +144,12 @@ bool IRGeneratorForStatements::visit(VariableDeclarationStatement const& _variab
|
|||||||
VariableDeclaration const* variableDeclaration = _variableDeclarationStatement.declarations().front().get();
|
VariableDeclaration const* variableDeclaration = _variableDeclarationStatement.declarations().front().get();
|
||||||
solAssert(variableDeclaration);
|
solAssert(variableDeclaration);
|
||||||
// TODO: check the type of the variable; register local variable; initialize
|
// TODO: check the type of the variable; register local variable; initialize
|
||||||
m_code << "let " << IRNames::localVariable(*variableDeclaration);
|
m_code << "let " << IRVariable{*variableDeclaration, type(*variableDeclaration)}.name();
|
||||||
if (_variableDeclarationStatement.initialValue())
|
if (_variableDeclarationStatement.initialValue())
|
||||||
m_code << " := " << IRNames::localVariable(*_variableDeclarationStatement.initialValue());
|
{
|
||||||
|
auto value = _variableDeclarationStatement.initialValue();
|
||||||
|
m_code << " := " << IRVariable{*value, type(*value)}.name();
|
||||||
|
}
|
||||||
m_code << "\n";
|
m_code << "\n";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -159,9 +162,7 @@ bool IRGeneratorForStatements::visit(ExpressionStatement const&)
|
|||||||
bool IRGeneratorForStatements::visit(Identifier const& _identifier)
|
bool IRGeneratorForStatements::visit(Identifier const& _identifier)
|
||||||
{
|
{
|
||||||
if (auto const* var = dynamic_cast<VariableDeclaration const*>(_identifier.annotation().referencedDeclaration))
|
if (auto const* var = dynamic_cast<VariableDeclaration const*>(_identifier.annotation().referencedDeclaration))
|
||||||
{
|
m_code << "let " << IRVariable{_identifier, type(_identifier)}.name() << " := " << IRVariable{*var, type(*var)}.name() << "\n";
|
||||||
m_code << "let " << IRNames::localVariable(_identifier) << " := " << IRNames::localVariable(*var) << "\n";
|
|
||||||
}
|
|
||||||
else if (auto const* function = dynamic_cast<FunctionDefinition const*>(_identifier.annotation().referencedDeclaration))
|
else if (auto const* function = dynamic_cast<FunctionDefinition const*>(_identifier.annotation().referencedDeclaration))
|
||||||
solAssert(m_expressionDeclaration.emplace(&_identifier, function).second);
|
solAssert(m_expressionDeclaration.emplace(&_identifier, function).second);
|
||||||
else if (auto const* typeClass = dynamic_cast<TypeClassDefinition const*>(_identifier.annotation().referencedDeclaration))
|
else if (auto const* typeClass = dynamic_cast<TypeClassDefinition const*>(_identifier.annotation().referencedDeclaration))
|
||||||
@ -179,7 +180,8 @@ void IRGeneratorForStatements::endVisit(Return const& _return)
|
|||||||
{
|
{
|
||||||
solAssert(_return.annotation().function, "Invalid return.");
|
solAssert(_return.annotation().function, "Invalid return.");
|
||||||
solAssert(_return.annotation().function->experimentalReturnExpression(), "Invalid return.");
|
solAssert(_return.annotation().function->experimentalReturnExpression(), "Invalid return.");
|
||||||
m_code << IRNames::localVariable(*_return.annotation().function->experimentalReturnExpression()) << " := " << IRNames::localVariable(*value) << "\n";
|
auto returnExpression = _return.annotation().function->experimentalReturnExpression();
|
||||||
|
m_code << IRVariable{*returnExpression, type(*returnExpression)}.name() << " := " << IRVariable{*value, type(*value)}.name() << "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
m_code << "leave\n";
|
m_code << "leave\n";
|
||||||
@ -206,8 +208,8 @@ void IRGeneratorForStatements::endVisit(BinaryOperation const& _binaryOperation)
|
|||||||
functionType = m_context.env->resolveRecursive(functionType);
|
functionType = m_context.env->resolveRecursive(functionType);
|
||||||
m_context.enqueueFunctionDefinition(&functionDefinition, functionType);
|
m_context.enqueueFunctionDefinition(&functionDefinition, functionType);
|
||||||
// TODO: account for return stack size
|
// TODO: account for return stack size
|
||||||
m_code << "let " << IRNames::localVariable(_binaryOperation) << " := " << IRNames::function(*m_context.env, functionDefinition, functionType) << "("
|
m_code << "let " << IRVariable{_binaryOperation, type(_binaryOperation)}.name() << " := " << IRNames::function(*m_context.env, functionDefinition, functionType) << "("
|
||||||
<< IRNames::localVariable(_binaryOperation.leftExpression()) << ", " << IRNames::localVariable(_binaryOperation.rightExpression()) << ")\n";
|
<< IRVariable{_binaryOperation.leftExpression(), type(_binaryOperation.leftExpression())}.name() << ", " << IRVariable{_binaryOperation.rightExpression(), type(_binaryOperation.rightExpression())}.name() << ")\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
@ -307,11 +309,11 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
|
|||||||
case Builtins::FromBool:
|
case Builtins::FromBool:
|
||||||
case Builtins::Identity:
|
case Builtins::Identity:
|
||||||
solAssert(_functionCall.arguments().size() == 1);
|
solAssert(_functionCall.arguments().size() == 1);
|
||||||
m_code << "let " << IRNames::localVariable(_functionCall) << " := " << IRNames::localVariable(*_functionCall.arguments().front()) << "\n";
|
m_code << "let " << IRVariable{_functionCall, type(_functionCall)}.name() << " := " << IRVariable{*_functionCall.arguments().front(), type(*_functionCall.arguments().front())}.name() << "\n";
|
||||||
return;
|
return;
|
||||||
case Builtins::ToBool:
|
case Builtins::ToBool:
|
||||||
solAssert(_functionCall.arguments().size() == 1);
|
solAssert(_functionCall.arguments().size() == 1);
|
||||||
m_code << "let " << IRNames::localVariable(_functionCall) << " := iszero(iszero(" << IRNames::localVariable(*_functionCall.arguments().front()) << "))\n";
|
m_code << "let " << IRVariable{_functionCall, type(_functionCall)}.name() << " := iszero(iszero(" << IRVariable{*_functionCall.arguments().front(), type(*_functionCall.arguments().front())}.name() << "))\n";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
solAssert(false);
|
solAssert(false);
|
||||||
@ -322,13 +324,13 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
|
|||||||
functionType = m_context.env->resolveRecursive(functionType);
|
functionType = m_context.env->resolveRecursive(functionType);
|
||||||
m_context.enqueueFunctionDefinition(functionDefinition, functionType);
|
m_context.enqueueFunctionDefinition(functionDefinition, functionType);
|
||||||
// TODO: account for return stack size
|
// TODO: account for return stack size
|
||||||
m_code << "let " << IRNames::localVariable(_functionCall) << " := " << IRNames::function(*m_context.env, *functionDefinition, functionType) << "(";
|
m_code << "let " << IRVariable{_functionCall, type(_functionCall)}.name() << " := " << IRNames::function(*m_context.env, *functionDefinition, functionType) << "(";
|
||||||
auto const& arguments = _functionCall.arguments();
|
auto const& arguments = _functionCall.arguments();
|
||||||
if (arguments.size() > 1)
|
if (arguments.size() > 1)
|
||||||
for (auto arg: arguments | ranges::views::drop_last(1))
|
for (auto arg: arguments | ranges::views::drop_last(1))
|
||||||
m_code << IRNames::localVariable(*arg) << ", ";
|
m_code << IRVariable{*arg, type(*arg)}.name() << ", ";
|
||||||
if (!arguments.empty())
|
if (!arguments.empty())
|
||||||
m_code << IRNames::localVariable(*arguments.back());
|
m_code << IRVariable{*arguments.back(), type(*arguments.back())}.name();
|
||||||
m_code << ")\n";
|
m_code << ")\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -352,7 +354,7 @@ bool IRGeneratorForStatements::visit(IfStatement const& _ifStatement)
|
|||||||
_ifStatement.condition().accept(*this);
|
_ifStatement.condition().accept(*this);
|
||||||
if (_ifStatement.falseStatement())
|
if (_ifStatement.falseStatement())
|
||||||
{
|
{
|
||||||
m_code << "switch " << IRNames::localVariable(_ifStatement.condition()) << " {\n";
|
m_code << "switch " << IRVariable{_ifStatement.condition(), type(_ifStatement.condition())}.name() << " {\n";
|
||||||
m_code << "case 0 {\n";
|
m_code << "case 0 {\n";
|
||||||
_ifStatement.falseStatement()->accept(*this);
|
_ifStatement.falseStatement()->accept(*this);
|
||||||
m_code << "}\n";
|
m_code << "}\n";
|
||||||
@ -362,7 +364,7 @@ bool IRGeneratorForStatements::visit(IfStatement const& _ifStatement)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_code << "if " << IRNames::localVariable(_ifStatement.condition()) << " {\n";
|
m_code << "if " << IRVariable{_ifStatement.condition(), type(_ifStatement.condition())}.name() << " {\n";
|
||||||
_ifStatement.trueStatement().accept(*this);
|
_ifStatement.trueStatement().accept(*this);
|
||||||
m_code << "}\n";
|
m_code << "}\n";
|
||||||
}
|
}
|
||||||
@ -376,9 +378,9 @@ bool IRGeneratorForStatements::visit(Assignment const& _assignment)
|
|||||||
solAssert(lhs, "Can only assign to identifiers.");
|
solAssert(lhs, "Can only assign to identifiers.");
|
||||||
auto const* lhsVar = dynamic_cast<VariableDeclaration const*>(lhs->annotation().referencedDeclaration);
|
auto const* lhsVar = dynamic_cast<VariableDeclaration const*>(lhs->annotation().referencedDeclaration);
|
||||||
solAssert(lhsVar, "Can only assign to identifiers referring to variables.");
|
solAssert(lhsVar, "Can only assign to identifiers referring to variables.");
|
||||||
m_code << IRNames::localVariable(*lhsVar) << " := " << IRNames::localVariable(_assignment.rightHandSide()) << "\n";
|
m_code << IRVariable{*lhsVar, type(*lhsVar)}.name() << " := " << IRVariable{_assignment.rightHandSide(), type(_assignment.rightHandSide())}.name() << "\n";
|
||||||
|
|
||||||
m_code << "let " << IRNames::localVariable(_assignment) << " := " << IRNames::localVariable(*lhsVar) << "\n";
|
m_code << "let " << IRVariable{_assignment, type(_assignment)}.name() << " := " << IRVariable{*lhsVar, type(*lhsVar)}.name() << "\n";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
91
libsolidity/experimental/codegen/IRVariable.cpp
Normal file
91
libsolidity/experimental/codegen/IRVariable.cpp
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
/*
|
||||||
|
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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
// SPDX-License-Identifier: GPL-3.0
|
||||||
|
|
||||||
|
#include <libsolidity/experimental/analysis/TypeInference.h>
|
||||||
|
#include <libsolidity/experimental/codegen/Common.h>
|
||||||
|
#include <libsolidity/experimental/codegen/IRVariable.h>
|
||||||
|
|
||||||
|
#include <libsolutil/StringUtils.h>
|
||||||
|
|
||||||
|
using namespace solidity;
|
||||||
|
using namespace solidity::util;
|
||||||
|
using namespace solidity::frontend::experimental;
|
||||||
|
|
||||||
|
IRVariable::IRVariable(std::string _baseName, Type _type):
|
||||||
|
m_baseName(std::move(_baseName)), m_type(_type)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
IRVariable::IRVariable(VariableDeclaration const& _declaration, Type _type):
|
||||||
|
IRVariable(IRNames::localVariable(_declaration), _type)
|
||||||
|
{
|
||||||
|
solAssert(!_declaration.isStateVariable(), "");
|
||||||
|
}
|
||||||
|
|
||||||
|
IRVariable::IRVariable(Expression const& _expression, Type _type):
|
||||||
|
IRVariable(IRNames::localVariable(_expression), _type)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
IRVariable IRVariable::part(std::string const&) const
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
return IRVariable{"", Type{}};
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IRVariable::hasPart(std::string const&) const
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> IRVariable::stackSlots() const
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
return std::vector<std::string>{};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string IRVariable::commaSeparatedList() const
|
||||||
|
{
|
||||||
|
return joinHumanReadable(stackSlots());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string IRVariable::commaSeparatedListPrefixed() const
|
||||||
|
{
|
||||||
|
return joinHumanReadablePrefixed(stackSlots());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string IRVariable::name() const
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
return m_baseName;
|
||||||
|
}
|
||||||
|
|
||||||
|
IRVariable IRVariable::tupleComponent(size_t) const
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
return IRVariable{"", Type{}};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string IRVariable::suffixedName(std::string const& _suffix) const
|
||||||
|
{
|
||||||
|
if (_suffix.empty())
|
||||||
|
return m_baseName;
|
||||||
|
else
|
||||||
|
return m_baseName + '_' + _suffix;
|
||||||
|
}
|
90
libsolidity/experimental/codegen/IRVariable.h
Normal file
90
libsolidity/experimental/codegen/IRVariable.h
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
/*
|
||||||
|
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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
// SPDX-License-Identifier: GPL-3.0
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <libsolidity/ast/AST.h>
|
||||||
|
#include <libsolidity/experimental/codegen/IRGenerationContext.h>
|
||||||
|
#include <libsolidity/experimental/ast/Type.h>
|
||||||
|
|
||||||
|
#include <optional>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace solidity::frontend::experimental
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* An IRVariable refers to a set of yul variables that correspond to the stack layout of a Solidity variable or expression
|
||||||
|
* of a specific Solidity type. If the Solidity type occupies a single stack slot, the IRVariable refers to a single yul variable.
|
||||||
|
* Otherwise the set of yul variables it refers to is (recursively) determined by @see ``Type::stackItems()``.
|
||||||
|
* For example, an IRVariable referring to a dynamically sized calldata array will consist of two parts named
|
||||||
|
* ``offset`` and ``length``, whereas an IRVariable referring to a statically sized calldata type, a storage reference
|
||||||
|
* type or a memory reference type will contain a single unnamed part containing an offset. An IRVariable referring to
|
||||||
|
* a value type will contain a single unnamed part containing the value, an IRVariable referring to a tuple will
|
||||||
|
* have the typed tuple components as parts.
|
||||||
|
*/
|
||||||
|
class IRVariable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/// IR variable with explicit base name @a _baseName and type @a _type.
|
||||||
|
IRVariable(std::string _baseName, Type _type);
|
||||||
|
/// IR variable referring to the declaration @a _decl.
|
||||||
|
explicit IRVariable(VariableDeclaration const& _decl, Type _type);
|
||||||
|
/// IR variable referring to the expression @a _expr.
|
||||||
|
/// Intentionally not defined as explicit to allow defining IRVariables for expressions directly via implicit conversions.
|
||||||
|
IRVariable(Expression const& _expression, Type _type);
|
||||||
|
|
||||||
|
/// @returns the name of the variable, if it occupies a single stack slot (otherwise throws).
|
||||||
|
std::string name() const;
|
||||||
|
|
||||||
|
/// @returns a comma-separated list of the stack slots of the variable.
|
||||||
|
std::string commaSeparatedList() const;
|
||||||
|
|
||||||
|
/// @returns a comma-separated list of the stack slots of the variable that is
|
||||||
|
/// prefixed with a comma, unless it is empty.
|
||||||
|
std::string commaSeparatedListPrefixed() const;
|
||||||
|
|
||||||
|
/// @returns an IRVariable referring to the tuple component @a _i of a tuple variable.
|
||||||
|
IRVariable tupleComponent(std::size_t _i) const;
|
||||||
|
|
||||||
|
/// @returns the type of the variable.
|
||||||
|
Type type() const { return m_type; }
|
||||||
|
|
||||||
|
/// @returns an IRVariable referring to the stack component @a _slot of the variable.
|
||||||
|
/// @a _slot must be among the stack slots in ``m_type.stackItems()``.
|
||||||
|
/// The returned IRVariable is itself typed with the type of the stack slot as defined
|
||||||
|
/// in ``m_type.stackItems()`` and may again occupy multiple stack slots.
|
||||||
|
IRVariable part(std::string const& _slot) const;
|
||||||
|
|
||||||
|
/// @returns true if variable contains @a _name component
|
||||||
|
/// @a _name name of the component that is being checked
|
||||||
|
bool hasPart(std::string const& _name) const;
|
||||||
|
|
||||||
|
/// @returns a vector containing the names of the stack slots of the variable.
|
||||||
|
std::vector<std::string> stackSlots() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
/// @returns a name consisting of the base name appended with an underscore and @æ _suffix,
|
||||||
|
/// unless @a _suffix is empty, in which case the base name itself is returned.
|
||||||
|
std::string suffixedName(std::string const& _suffix) const;
|
||||||
|
std::string m_baseName;
|
||||||
|
Type m_type;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user