mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Use IRVariable's in IR code generation and implement tuples.
This commit is contained in:
@@ -31,23 +31,22 @@ using namespace solidity;
|
||||
using namespace solidity::util;
|
||||
using namespace solidity::frontend;
|
||||
|
||||
string IRGenerationContext::addLocalVariable(VariableDeclaration const& _varDecl)
|
||||
IRVariable const& IRGenerationContext::addLocalVariable(VariableDeclaration const& _varDecl)
|
||||
{
|
||||
solUnimplementedAssert(
|
||||
_varDecl.annotation().type->sizeOnStack() == 1,
|
||||
"Multi-slot types not yet implemented."
|
||||
auto const& [it, didInsert] = m_localVariables.emplace(
|
||||
std::make_pair(&_varDecl, IRVariable{_varDecl})
|
||||
);
|
||||
|
||||
return m_localVariables[&_varDecl] = "vloc_" + _varDecl.name() + "_" + to_string(_varDecl.id());
|
||||
solAssert(didInsert, "Local variable added multiple times.");
|
||||
return it->second;
|
||||
}
|
||||
|
||||
string IRGenerationContext::localVariableName(VariableDeclaration const& _varDecl)
|
||||
IRVariable const& IRGenerationContext::localVariable(VariableDeclaration const& _varDecl)
|
||||
{
|
||||
solAssert(
|
||||
m_localVariables.count(&_varDecl),
|
||||
"Unknown variable: " + _varDecl.name()
|
||||
);
|
||||
return m_localVariables[&_varDecl];
|
||||
return m_localVariables.at(&_varDecl);
|
||||
}
|
||||
|
||||
void IRGenerationContext::addStateVariable(
|
||||
@@ -98,23 +97,6 @@ string IRGenerationContext::newYulVariable()
|
||||
return "_" + to_string(++m_varCounter);
|
||||
}
|
||||
|
||||
string IRGenerationContext::variable(Expression const& _expression)
|
||||
{
|
||||
unsigned size = _expression.annotation().type->sizeOnStack();
|
||||
string var = "expr_" + to_string(_expression.id());
|
||||
if (size == 1)
|
||||
return var;
|
||||
else
|
||||
return suffixedVariableNameList(move(var) + "_", 1, 1 + size);
|
||||
}
|
||||
|
||||
string IRGenerationContext::variablePart(Expression const& _expression, string const& _part)
|
||||
{
|
||||
size_t numVars = _expression.annotation().type->sizeOnStack();
|
||||
solAssert(numVars > 1, "");
|
||||
return "expr_" + to_string(_expression.id()) + "_" + _part;
|
||||
}
|
||||
|
||||
string IRGenerationContext::internalDispatch(size_t _in, size_t _out)
|
||||
{
|
||||
string funName = "dispatch_internal_in_" + to_string(_in) + "_out_" + to_string(_out);
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <libsolidity/codegen/ir/IRVariable.h>
|
||||
#include <libsolidity/interface/OptimiserSettings.h>
|
||||
#include <libsolidity/interface/DebugSettings.h>
|
||||
|
||||
@@ -68,9 +69,9 @@ public:
|
||||
}
|
||||
|
||||
|
||||
std::string addLocalVariable(VariableDeclaration const& _varDecl);
|
||||
IRVariable const& addLocalVariable(VariableDeclaration const& _varDecl);
|
||||
bool isLocalVariable(VariableDeclaration const& _varDecl) const { return m_localVariables.count(&_varDecl); }
|
||||
std::string localVariableName(VariableDeclaration const& _varDecl);
|
||||
IRVariable const& localVariable(VariableDeclaration const& _varDecl);
|
||||
|
||||
void addStateVariable(VariableDeclaration const& _varDecl, u256 _storageOffset, unsigned _byteOffset);
|
||||
bool isStateVariable(VariableDeclaration const& _varDecl) const { return m_stateVariables.count(&_varDecl); }
|
||||
@@ -85,11 +86,6 @@ public:
|
||||
std::string virtualFunctionName(FunctionDefinition const& _functionDeclaration);
|
||||
|
||||
std::string newYulVariable();
|
||||
/// @returns the variable (or comma-separated list of variables) that contain
|
||||
/// the value of the given expression.
|
||||
std::string variable(Expression const& _expression);
|
||||
/// @returns the sub-variable of a multi-variable expression.
|
||||
std::string variablePart(Expression const& _expression, std::string const& _part);
|
||||
|
||||
std::string internalDispatch(size_t _in, size_t _out);
|
||||
|
||||
@@ -109,7 +105,7 @@ private:
|
||||
RevertStrings m_revertStrings;
|
||||
OptimiserSettings m_optimiserSettings;
|
||||
std::vector<ContractDefinition const*> m_inheritanceHierarchy;
|
||||
std::map<VariableDeclaration const*, std::string> m_localVariables;
|
||||
std::map<VariableDeclaration const*, IRVariable> m_localVariables;
|
||||
/// Storage offsets of state variables
|
||||
std::map<VariableDeclaration const*, std::pair<u256, unsigned>> m_stateVariables;
|
||||
std::shared_ptr<MultiUseYulFunctionCollector> m_functions;
|
||||
|
||||
@@ -139,11 +139,11 @@ string IRGenerator::generateFunction(FunctionDefinition const& _function)
|
||||
t("functionName", functionName);
|
||||
string params;
|
||||
for (auto const& varDecl: _function.parameters())
|
||||
params += (params.empty() ? "" : ", ") + m_context.addLocalVariable(*varDecl);
|
||||
params += (params.empty() ? "" : ", ") + m_context.addLocalVariable(*varDecl).commaSeparatedList();
|
||||
t("params", params);
|
||||
string retParams;
|
||||
for (auto const& varDecl: _function.returnParameters())
|
||||
retParams += (retParams.empty() ? "" : ", ") + m_context.addLocalVariable(*varDecl);
|
||||
retParams += (retParams.empty() ? "" : ", ") + m_context.addLocalVariable(*varDecl).commaSeparatedList();
|
||||
t("returns", retParams.empty() ? "" : " -> " + retParams);
|
||||
t("body", generate(_function.body()));
|
||||
return t.render();
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -22,6 +22,7 @@
|
||||
|
||||
#include <libsolidity/ast/ASTVisitor.h>
|
||||
#include <libsolidity/codegen/ir/IRLValue.h>
|
||||
#include <libsolidity/codegen/ir/IRVariable.h>
|
||||
|
||||
namespace solidity::frontend
|
||||
{
|
||||
@@ -75,12 +76,25 @@ private:
|
||||
|
||||
std::string fetchFreeMem() const;
|
||||
|
||||
/// Generates the required conversion code and @returns an IRVariable referring to the value of @a _variable
|
||||
/// converted to type @a _to.
|
||||
IRVariable convert(IRVariable const& _variable, Type const& _to);
|
||||
|
||||
/// @returns a Yul expression representing the current value of @a _expression,
|
||||
/// converted to type @a _to if it does not yet have that type.
|
||||
std::string expressionAsType(Expression const& _expression, Type const& _to);
|
||||
std::ostream& defineExpression(Expression const& _expression);
|
||||
/// Defines only one of many variables corresponding to an expression.
|
||||
std::ostream& defineExpressionPart(Expression const& _expression, std::string const& _part);
|
||||
|
||||
/// @returns an output stream that can be used to define @a _var using a function call or
|
||||
/// single stack slot expression.
|
||||
std::ostream& define(IRVariable const& _var);
|
||||
/// Defines @a _var using the value of @a _value while performing type conversions, if required.
|
||||
void define(IRVariable const& _var, IRVariable const& _value) { declareAssign(_var, _value, true); }
|
||||
/// Assigns @a _var to the value of @a _value while performing type conversions, if required.
|
||||
void assign(IRVariable const& _var, IRVariable const& _value) { declareAssign(_var, _value, false); }
|
||||
/// Declares variable @a _var.
|
||||
void declare(IRVariable const& _var);
|
||||
|
||||
void declareAssign(IRVariable const& _var, IRVariable const& _value, bool _define);
|
||||
|
||||
void appendAndOrOperatorCode(BinaryOperation const& _binOp);
|
||||
void appendSimpleUnaryOperation(UnaryOperation const& _operation, Expression const& _expr);
|
||||
@@ -93,7 +107,14 @@ private:
|
||||
std::string const& _right
|
||||
);
|
||||
|
||||
void setLValue(Expression const& _expression, std::unique_ptr<IRLValue> _lvalue);
|
||||
/// Assigns the value of @a _value to the lvalue @a _lvalue.
|
||||
void writeToLValue(IRLValue const& _lvalue, IRVariable const& _value);
|
||||
/// @returns a fresh IR variable containing the value of the lvalue @a _lvalue.
|
||||
IRVariable readFromLValue(IRLValue const& _lvalue);
|
||||
|
||||
/// Stores the given @a _lvalue in m_currentLValue, if it will be written to (lValueRequested). Otherwise
|
||||
/// defines the expression @a _expression by reading the value from @a _lvalue.
|
||||
void setLValue(Expression const& _expression, IRLValue _lvalue);
|
||||
void generateLoop(
|
||||
Statement const& _body,
|
||||
Expression const* _conditionExpression,
|
||||
@@ -107,7 +128,7 @@ private:
|
||||
std::ostringstream m_code;
|
||||
IRGenerationContext& m_context;
|
||||
YulUtilFunctions& m_utils;
|
||||
std::unique_ptr<IRLValue> m_currentLValue;
|
||||
std::optional<IRLValue> m_currentLValue;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -1,228 +0,0 @@
|
||||
/*
|
||||
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/>.
|
||||
*/
|
||||
/**
|
||||
* Generator for code that handles LValues.
|
||||
*/
|
||||
|
||||
#include <libsolidity/codegen/ir/IRLValue.h>
|
||||
|
||||
#include <libsolidity/codegen/ir/IRGenerationContext.h>
|
||||
#include <libsolidity/codegen/YulUtilFunctions.h>
|
||||
#include <libsolidity/codegen/CompilerUtils.h>
|
||||
#include <libsolidity/ast/AST.h>
|
||||
|
||||
#include <libsolutil/Whiskers.h>
|
||||
|
||||
using namespace std;
|
||||
using namespace solidity;
|
||||
using namespace solidity::frontend;
|
||||
|
||||
IRLocalVariable::IRLocalVariable(
|
||||
IRGenerationContext& _context,
|
||||
VariableDeclaration const& _varDecl
|
||||
):
|
||||
IRLValue(_context.utils(), _varDecl.annotation().type),
|
||||
m_variableName(_context.localVariableName(_varDecl))
|
||||
{
|
||||
}
|
||||
|
||||
string IRLocalVariable::storeValue(string const& _value, Type const& _type) const
|
||||
{
|
||||
solAssert(_type == *m_type, "Storing different types - not necessarily a problem.");
|
||||
return m_variableName + " := " + _value + "\n";
|
||||
}
|
||||
|
||||
string IRLocalVariable::setToZero() const
|
||||
{
|
||||
return storeValue(m_utils.zeroValueFunction(*m_type) + "()", *m_type);
|
||||
}
|
||||
|
||||
IRStorageItem::IRStorageItem(
|
||||
IRGenerationContext& _context,
|
||||
VariableDeclaration const& _varDecl
|
||||
):
|
||||
IRStorageItem(
|
||||
_context.utils(),
|
||||
*_varDecl.annotation().type,
|
||||
_context.storageLocationOfVariable(_varDecl)
|
||||
)
|
||||
{ }
|
||||
|
||||
IRStorageItem::IRStorageItem(
|
||||
YulUtilFunctions _utils,
|
||||
Type const& _type,
|
||||
std::pair<u256, unsigned> slot_offset
|
||||
):
|
||||
IRLValue(std::move(_utils), &_type),
|
||||
m_slot(util::toCompactHexWithPrefix(slot_offset.first)),
|
||||
m_offset(slot_offset.second)
|
||||
{
|
||||
}
|
||||
|
||||
IRStorageItem::IRStorageItem(
|
||||
YulUtilFunctions _utils,
|
||||
string _slot,
|
||||
boost::variant<string, unsigned> _offset,
|
||||
Type const& _type
|
||||
):
|
||||
IRLValue(std::move(_utils), &_type),
|
||||
m_slot(std::move(_slot)),
|
||||
m_offset(std::move(_offset))
|
||||
{
|
||||
solAssert(!m_offset.empty(), "");
|
||||
solAssert(!m_slot.empty(), "");
|
||||
}
|
||||
|
||||
string IRStorageItem::retrieveValue() const
|
||||
{
|
||||
if (!m_type->isValueType())
|
||||
return m_slot;
|
||||
solUnimplementedAssert(m_type->category() != Type::Category::Function, "");
|
||||
if (m_offset.type() == typeid(string))
|
||||
return
|
||||
m_utils.readFromStorageDynamic(*m_type, false) +
|
||||
"(" +
|
||||
m_slot +
|
||||
", " +
|
||||
boost::get<string>(m_offset) +
|
||||
")";
|
||||
else if (m_offset.type() == typeid(unsigned))
|
||||
return
|
||||
m_utils.readFromStorage(*m_type, boost::get<unsigned>(m_offset), false) +
|
||||
"(" +
|
||||
m_slot +
|
||||
")";
|
||||
|
||||
solAssert(false, "");
|
||||
}
|
||||
|
||||
string IRStorageItem::storeValue(string const& _value, Type const& _sourceType) const
|
||||
{
|
||||
if (m_type->isValueType())
|
||||
solAssert(_sourceType == *m_type, "Different type, but might not be an error.");
|
||||
|
||||
std::optional<unsigned> offset;
|
||||
|
||||
if (m_offset.type() == typeid(unsigned))
|
||||
offset = get<unsigned>(m_offset);
|
||||
|
||||
return
|
||||
m_utils.updateStorageValueFunction(*m_type, offset) +
|
||||
"(" +
|
||||
m_slot +
|
||||
(m_offset.type() == typeid(string) ?
|
||||
(", " + get<string>(m_offset)) :
|
||||
""
|
||||
) +
|
||||
", " +
|
||||
_value +
|
||||
")\n";
|
||||
}
|
||||
|
||||
string IRStorageItem::setToZero() const
|
||||
{
|
||||
return
|
||||
m_utils.storageSetToZeroFunction(*m_type) +
|
||||
"(" +
|
||||
m_slot +
|
||||
", " +
|
||||
(
|
||||
m_offset.type() == typeid(unsigned) ?
|
||||
to_string(get<unsigned>(m_offset)) :
|
||||
get<string>(m_offset)
|
||||
) +
|
||||
")\n";
|
||||
}
|
||||
|
||||
IRMemoryItem::IRMemoryItem(
|
||||
YulUtilFunctions _utils,
|
||||
std::string _address,
|
||||
bool _byteArrayElement,
|
||||
Type const& _type
|
||||
):
|
||||
IRLValue(std::move(_utils), &_type),
|
||||
m_address(move(_address)),
|
||||
m_byteArrayElement(_byteArrayElement)
|
||||
{ }
|
||||
|
||||
string IRMemoryItem::retrieveValue() const
|
||||
{
|
||||
if (m_byteArrayElement)
|
||||
return m_utils.cleanupFunction(*m_type) +
|
||||
"(mload(" +
|
||||
m_address +
|
||||
"))";
|
||||
|
||||
if (m_type->isValueType())
|
||||
return m_utils.readFromMemory(*m_type) +
|
||||
"(" +
|
||||
m_address +
|
||||
")";
|
||||
else
|
||||
return "mload(" + m_address + ")";
|
||||
}
|
||||
|
||||
string IRMemoryItem::storeValue(string const& _value, Type const& _type) const
|
||||
{
|
||||
if (!m_type->isValueType())
|
||||
{
|
||||
solUnimplementedAssert(_type == *m_type, "Conversion not implemented for assignment to memory.");
|
||||
|
||||
solAssert(m_type->sizeOnStack() == 1, "");
|
||||
solAssert(dynamic_cast<ReferenceType const*>(m_type), "");
|
||||
|
||||
return "mstore(" + m_address + ", " + _value + ")\n";
|
||||
}
|
||||
|
||||
solAssert(_type.isValueType(), "");
|
||||
|
||||
string prepared = _value;
|
||||
|
||||
// Exists to see if this case ever happens
|
||||
solAssert(_type == *m_type, "");
|
||||
|
||||
if (_type != *m_type)
|
||||
prepared =
|
||||
m_utils.conversionFunction(_type, *m_type) +
|
||||
"(" +
|
||||
_value +
|
||||
")";
|
||||
else
|
||||
prepared =
|
||||
m_utils.cleanupFunction(*m_type) +
|
||||
"(" +
|
||||
_value +
|
||||
")";
|
||||
|
||||
if (m_byteArrayElement)
|
||||
{
|
||||
solAssert(*m_type == *TypeProvider::byte(), "");
|
||||
return "mstore8(" + m_address + ", byte(0, " + prepared + "))\n";
|
||||
}
|
||||
else
|
||||
return m_utils.writeToMemoryFunction(*m_type) +
|
||||
"(" +
|
||||
m_address +
|
||||
", " +
|
||||
prepared +
|
||||
")\n";
|
||||
}
|
||||
|
||||
string IRMemoryItem::setToZero() const
|
||||
{
|
||||
return storeValue(m_utils.zeroValueFunction(*m_type) + "()", *m_type);
|
||||
}
|
||||
@@ -15,115 +15,51 @@
|
||||
along with solidity. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/**
|
||||
* Generator for code that handles LValues.
|
||||
* Classes that store locations of lvalues.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <libsolidity/codegen/YulUtilFunctions.h>
|
||||
|
||||
#include <libsolutil/Common.h>
|
||||
|
||||
#include <string>
|
||||
#include <ostream>
|
||||
#include <boost/variant.hpp>
|
||||
#include <libsolidity/codegen/ir/IRVariable.h>
|
||||
#include <variant>
|
||||
|
||||
namespace solidity::frontend
|
||||
{
|
||||
|
||||
class VariableDeclaration;
|
||||
class IRGenerationContext;
|
||||
class Type;
|
||||
class ArrayType;
|
||||
|
||||
/**
|
||||
* Abstract class used to retrieve, delete and store data in LValues.
|
||||
*/
|
||||
class IRLValue
|
||||
struct IRLValue
|
||||
{
|
||||
protected:
|
||||
explicit IRLValue(YulUtilFunctions _utils, Type const* _type = nullptr):
|
||||
m_utils(std::move(_utils)),
|
||||
m_type(_type)
|
||||
{}
|
||||
|
||||
public:
|
||||
virtual ~IRLValue() = default;
|
||||
/// @returns an expression to retrieve the value of the lvalue.
|
||||
virtual std::string retrieveValue() const = 0;
|
||||
/// Returns code that stores the value of @a _value (should be an identifier)
|
||||
/// of type @a _type in the lvalue. Might perform type conversion.
|
||||
virtual std::string storeValue(std::string const& _value, Type const& _type) const = 0;
|
||||
|
||||
/// Returns code that will reset the stored value to zero
|
||||
virtual std::string setToZero() const = 0;
|
||||
protected:
|
||||
YulUtilFunctions mutable m_utils;
|
||||
Type const* m_type;
|
||||
Type const& type;
|
||||
struct Stack
|
||||
{
|
||||
IRVariable variable;
|
||||
};
|
||||
struct Storage
|
||||
{
|
||||
std::string const slot;
|
||||
/// unsigned: Used when the offset is known at compile time, uses optimized
|
||||
/// functions
|
||||
/// string: Used when the offset is determined at run time
|
||||
std::variant<std::string, unsigned> const offset;
|
||||
std::string offsetString() const
|
||||
{
|
||||
if (std::holds_alternative<unsigned>(offset))
|
||||
return std::to_string(std::get<unsigned>(offset));
|
||||
else
|
||||
return std::get<std::string>(offset);
|
||||
}
|
||||
};
|
||||
struct Memory
|
||||
{
|
||||
std::string const address;
|
||||
bool byteArrayElement = false;
|
||||
};
|
||||
struct Tuple
|
||||
{
|
||||
std::vector<std::optional<IRLValue>> components;
|
||||
};
|
||||
std::variant<Stack, Storage, Memory, Tuple> kind;
|
||||
};
|
||||
|
||||
class IRLocalVariable: public IRLValue
|
||||
{
|
||||
public:
|
||||
IRLocalVariable(
|
||||
IRGenerationContext& _context,
|
||||
VariableDeclaration const& _varDecl
|
||||
);
|
||||
std::string retrieveValue() const override { return m_variableName; }
|
||||
std::string storeValue(std::string const& _value, Type const& _type) const override;
|
||||
|
||||
std::string setToZero() const override;
|
||||
private:
|
||||
std::string m_variableName;
|
||||
};
|
||||
|
||||
class IRStorageItem: public IRLValue
|
||||
{
|
||||
public:
|
||||
IRStorageItem(
|
||||
IRGenerationContext& _context,
|
||||
VariableDeclaration const& _varDecl
|
||||
);
|
||||
IRStorageItem(
|
||||
YulUtilFunctions _utils,
|
||||
std::string _slot,
|
||||
boost::variant<std::string, unsigned> _offset,
|
||||
Type const& _type
|
||||
);
|
||||
std::string retrieveValue() const override;
|
||||
std::string storeValue(std::string const& _value, Type const& _type) const override;
|
||||
|
||||
std::string setToZero() const override;
|
||||
private:
|
||||
IRStorageItem(
|
||||
YulUtilFunctions _utils,
|
||||
Type const& _type,
|
||||
std::pair<u256, unsigned> slot_offset
|
||||
);
|
||||
|
||||
std::string const m_slot;
|
||||
/// unsigned: Used when the offset is known at compile time, uses optimized
|
||||
/// functions
|
||||
/// string: Used when the offset is determined at run time
|
||||
boost::variant<std::string, unsigned> const m_offset;
|
||||
};
|
||||
|
||||
class IRMemoryItem: public IRLValue
|
||||
{
|
||||
public:
|
||||
IRMemoryItem(
|
||||
YulUtilFunctions _utils,
|
||||
std::string _address,
|
||||
bool _byteArrayElement,
|
||||
Type const& _type
|
||||
);
|
||||
std::string retrieveValue() const override;
|
||||
std::string storeValue(std::string const& _value, Type const& _type) const override;
|
||||
|
||||
std::string setToZero() const override;
|
||||
private:
|
||||
std::string const m_address;
|
||||
bool m_byteArrayElement;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
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/>.
|
||||
*/
|
||||
#include <libsolidity/codegen/ir/IRVariable.h>
|
||||
#include <libsolidity/ast/AST.h>
|
||||
#include <boost/range/adaptor/transformed.hpp>
|
||||
#include <libsolutil/StringUtils.h>
|
||||
|
||||
using namespace std;
|
||||
using namespace solidity;
|
||||
using namespace solidity::frontend;
|
||||
using namespace solidity::util;
|
||||
|
||||
IRVariable::IRVariable(std::string _baseName, Type const& _type):
|
||||
m_baseName(std::move(_baseName)), m_type(_type)
|
||||
{
|
||||
}
|
||||
|
||||
IRVariable::IRVariable(VariableDeclaration const& _declaration):
|
||||
IRVariable(
|
||||
"vloc_" + _declaration.name() + '_' + std::to_string(_declaration.id()),
|
||||
*_declaration.annotation().type
|
||||
)
|
||||
{
|
||||
solAssert(!_declaration.isStateVariable(), "");
|
||||
}
|
||||
|
||||
IRVariable::IRVariable(Expression const& _expression):
|
||||
IRVariable(
|
||||
"expr_" + to_string(_expression.id()),
|
||||
*_expression.annotation().type
|
||||
)
|
||||
{
|
||||
}
|
||||
|
||||
IRVariable IRVariable::part(string const& _name) const
|
||||
{
|
||||
for (auto const& [itemName, itemType]: m_type.stackItems())
|
||||
if (itemName == _name)
|
||||
{
|
||||
solAssert(itemName.empty() || itemType, "");
|
||||
return IRVariable{suffixedName(itemName), itemType ? *itemType : m_type};
|
||||
}
|
||||
solAssert(false, "Invalid stack item name.");
|
||||
}
|
||||
|
||||
vector<string> IRVariable::stackSlots() const
|
||||
{
|
||||
vector<string> result;
|
||||
for (auto const& [itemName, itemType]: m_type.stackItems())
|
||||
if (itemType)
|
||||
{
|
||||
solAssert(!itemName.empty(), "");
|
||||
solAssert(m_type != *itemType, "");
|
||||
result += IRVariable{suffixedName(itemName), *itemType}.stackSlots();
|
||||
}
|
||||
else
|
||||
{
|
||||
solAssert(itemName.empty(), "");
|
||||
result.emplace_back(m_baseName);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
string IRVariable::commaSeparatedList() const
|
||||
{
|
||||
return joinHumanReadable(stackSlots());
|
||||
}
|
||||
|
||||
string IRVariable::commaSeparatedListPrefixed() const
|
||||
{
|
||||
return joinHumanReadablePrefixed(stackSlots());
|
||||
}
|
||||
|
||||
string IRVariable::name() const
|
||||
{
|
||||
solAssert(m_type.sizeOnStack() == 1, "");
|
||||
auto const& [itemName, type] = m_type.stackItems().front();
|
||||
solAssert(!type, "");
|
||||
return suffixedName(itemName);
|
||||
}
|
||||
|
||||
IRVariable IRVariable::tupleComponent(size_t _i) const
|
||||
{
|
||||
solAssert(
|
||||
m_type.category() == Type::Category::Tuple,
|
||||
"Requested tuple component of non-tuple IR variable."
|
||||
);
|
||||
return part("component_" + std::to_string(_i + 1));
|
||||
}
|
||||
|
||||
string IRVariable::suffixedName(string const& _suffix) const
|
||||
{
|
||||
if (_suffix.empty())
|
||||
return m_baseName;
|
||||
else
|
||||
return m_baseName + '_' + _suffix;
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
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/>.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace solidity::frontend
|
||||
{
|
||||
|
||||
class VariableDeclaration;
|
||||
class Type;
|
||||
class Expression;
|
||||
|
||||
/**
|
||||
* An IRVariable refers to a set of yul variables that correspond to the stack layout of a Solidity variable or expression
|
||||
* of a specific S
|
||||
* olidity 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 const& _type);
|
||||
/// IR variable referring to the declaration @a _decl.
|
||||
explicit IRVariable(VariableDeclaration const& _decl);
|
||||
/// 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);
|
||||
|
||||
/// @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 const& 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;
|
||||
private:
|
||||
/// @returns a vector containing the names of the stack slots of the variable.
|
||||
std::vector<std::string> stackSlots() const;
|
||||
|
||||
/// @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 const& m_type;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user