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/codegen/Common.h
|
||||
experimental/codegen/Common.cpp
|
||||
experimental/codegen/IRVariable.cpp
|
||||
experimental/codegen/IRVariable.h
|
||||
experimental/codegen/IRGenerationContext.h
|
||||
experimental/codegen/IRGenerator.cpp
|
||||
experimental/codegen/IRGenerator.h
|
||||
|
@ -101,7 +101,7 @@ private:
|
||||
auto type = m_context.analysis.annotation<TypeInference>(*varDecl).type;
|
||||
solAssert(type);
|
||||
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}};
|
||||
}
|
||||
|
||||
@ -119,7 +119,7 @@ bool IRGeneratorForStatements::visit(TupleExpression const& _tupleExpression)
|
||||
{
|
||||
solUnimplementedAssert(component);
|
||||
component->accept(*this);
|
||||
components.emplace_back(IRNames::localVariable(*component));
|
||||
components.emplace_back(IRVariable{*component, type(*component)}.name());
|
||||
}
|
||||
|
||||
solUnimplementedAssert(false, "No support for tuples.");
|
||||
@ -144,9 +144,12 @@ bool IRGeneratorForStatements::visit(VariableDeclarationStatement const& _variab
|
||||
VariableDeclaration const* variableDeclaration = _variableDeclarationStatement.declarations().front().get();
|
||||
solAssert(variableDeclaration);
|
||||
// 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())
|
||||
m_code << " := " << IRNames::localVariable(*_variableDeclarationStatement.initialValue());
|
||||
{
|
||||
auto value = _variableDeclarationStatement.initialValue();
|
||||
m_code << " := " << IRVariable{*value, type(*value)}.name();
|
||||
}
|
||||
m_code << "\n";
|
||||
return false;
|
||||
}
|
||||
@ -159,9 +162,7 @@ bool IRGeneratorForStatements::visit(ExpressionStatement const&)
|
||||
bool IRGeneratorForStatements::visit(Identifier const& _identifier)
|
||||
{
|
||||
if (auto const* var = dynamic_cast<VariableDeclaration const*>(_identifier.annotation().referencedDeclaration))
|
||||
{
|
||||
m_code << "let " << IRNames::localVariable(_identifier) << " := " << IRNames::localVariable(*var) << "\n";
|
||||
}
|
||||
m_code << "let " << IRVariable{_identifier, type(_identifier)}.name() << " := " << IRVariable{*var, type(*var)}.name() << "\n";
|
||||
else if (auto const* function = dynamic_cast<FunctionDefinition const*>(_identifier.annotation().referencedDeclaration))
|
||||
solAssert(m_expressionDeclaration.emplace(&_identifier, function).second);
|
||||
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->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";
|
||||
@ -206,8 +208,8 @@ void IRGeneratorForStatements::endVisit(BinaryOperation const& _binaryOperation)
|
||||
functionType = m_context.env->resolveRecursive(functionType);
|
||||
m_context.enqueueFunctionDefinition(&functionDefinition, functionType);
|
||||
// TODO: account for return stack size
|
||||
m_code << "let " << IRNames::localVariable(_binaryOperation) << " := " << IRNames::function(*m_context.env, functionDefinition, functionType) << "("
|
||||
<< IRNames::localVariable(_binaryOperation.leftExpression()) << ", " << IRNames::localVariable(_binaryOperation.rightExpression()) << ")\n";
|
||||
m_code << "let " << IRVariable{_binaryOperation, type(_binaryOperation)}.name() << " := " << IRNames::function(*m_context.env, functionDefinition, functionType) << "("
|
||||
<< IRVariable{_binaryOperation.leftExpression(), type(_binaryOperation.leftExpression())}.name() << ", " << IRVariable{_binaryOperation.rightExpression(), type(_binaryOperation.rightExpression())}.name() << ")\n";
|
||||
}
|
||||
|
||||
namespace
|
||||
@ -307,11 +309,11 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
|
||||
case Builtins::FromBool:
|
||||
case Builtins::Identity:
|
||||
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;
|
||||
case Builtins::ToBool:
|
||||
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;
|
||||
}
|
||||
solAssert(false);
|
||||
@ -322,13 +324,13 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
|
||||
functionType = m_context.env->resolveRecursive(functionType);
|
||||
m_context.enqueueFunctionDefinition(functionDefinition, functionType);
|
||||
// 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();
|
||||
if (arguments.size() > 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())
|
||||
m_code << IRNames::localVariable(*arguments.back());
|
||||
m_code << IRVariable{*arguments.back(), type(*arguments.back())}.name();
|
||||
m_code << ")\n";
|
||||
}
|
||||
|
||||
@ -352,7 +354,7 @@ bool IRGeneratorForStatements::visit(IfStatement const& _ifStatement)
|
||||
_ifStatement.condition().accept(*this);
|
||||
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";
|
||||
_ifStatement.falseStatement()->accept(*this);
|
||||
m_code << "}\n";
|
||||
@ -362,7 +364,7 @@ bool IRGeneratorForStatements::visit(IfStatement const& _ifStatement)
|
||||
}
|
||||
else
|
||||
{
|
||||
m_code << "if " << IRNames::localVariable(_ifStatement.condition()) << " {\n";
|
||||
m_code << "if " << IRVariable{_ifStatement.condition(), type(_ifStatement.condition())}.name() << " {\n";
|
||||
_ifStatement.trueStatement().accept(*this);
|
||||
m_code << "}\n";
|
||||
}
|
||||
@ -376,9 +378,9 @@ bool IRGeneratorForStatements::visit(Assignment const& _assignment)
|
||||
solAssert(lhs, "Can only assign to identifiers.");
|
||||
auto const* lhsVar = dynamic_cast<VariableDeclaration const*>(lhs->annotation().referencedDeclaration);
|
||||
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;
|
||||
}
|
||||
|
||||
|
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