mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
LValues and state variables of value type.
This commit is contained in:
parent
dcca6f6318
commit
aa4d4afcdc
@ -73,6 +73,8 @@ set(sources
|
||||
codegen/ir/IRGeneratorForStatements.h
|
||||
codegen/ir/IRGenerationContext.cpp
|
||||
codegen/ir/IRGenerationContext.h
|
||||
codegen/ir/IRLValue.cpp
|
||||
codegen/ir/IRLValue.h
|
||||
formal/EncodingContext.cpp
|
||||
formal/EncodingContext.h
|
||||
formal/SMTChecker.cpp
|
||||
|
@ -237,6 +237,30 @@ string YulUtilFunctions::shiftRightFunction(size_t _numBits)
|
||||
}
|
||||
}
|
||||
|
||||
string YulUtilFunctions::updateByteSliceFunction(size_t _numBytes, size_t _shiftBytes)
|
||||
{
|
||||
solAssert(_numBytes <= 32, "");
|
||||
solAssert(_shiftBytes <= 32, "");
|
||||
size_t numBits = _numBytes * 8;
|
||||
size_t shiftBits = _shiftBytes * 8;
|
||||
string functionName = "update_byte_slice_" + to_string(_numBytes) + "_shift_" + to_string(_shiftBytes);
|
||||
return m_functionCollector->createFunction(functionName, [&]() {
|
||||
return
|
||||
Whiskers(R"(
|
||||
function <functionName>(value, toInsert) -> result {
|
||||
let mask := <mask>
|
||||
toInsert := <shl>(toInsert)
|
||||
value := and(value, not(mask))
|
||||
result := or(value, and(toInsert, mask))
|
||||
}
|
||||
)")
|
||||
("functionName", functionName)
|
||||
("mask", formatNumber(((bigint(1) << numBits) - 1) << shiftBits))
|
||||
("shl", shiftLeftFunction(shiftBits))
|
||||
.render();
|
||||
});
|
||||
}
|
||||
|
||||
string YulUtilFunctions::roundUpFunction()
|
||||
{
|
||||
string functionName = "round_up_to_mul_of_32";
|
||||
@ -541,6 +565,26 @@ string YulUtilFunctions::cleanupFromStorageFunction(Type const& _type, bool _spl
|
||||
});
|
||||
}
|
||||
|
||||
string YulUtilFunctions::prepareStoreFunction(Type const& _type)
|
||||
{
|
||||
solUnimplementedAssert(_type.category() != Type::Category::Function, "");
|
||||
|
||||
string functionName = "prepare_store_" + _type.identifier();
|
||||
return m_functionCollector->createFunction(functionName, [&]() {
|
||||
Whiskers templ(R"(
|
||||
function <functionName>(value) -> ret {
|
||||
ret := <actualPrepare>
|
||||
}
|
||||
)");
|
||||
templ("functionName", functionName);
|
||||
if (_type.category() == Type::Category::FixedBytes)
|
||||
templ("actualPrepare", shiftRightFunction(256 - 8 * _type.storageBytes()) + "(value)");
|
||||
else
|
||||
templ("actualPrepare", "value");
|
||||
return templ.render();
|
||||
});
|
||||
}
|
||||
|
||||
string YulUtilFunctions::allocationFunction()
|
||||
{
|
||||
string functionName = "allocateMemory";
|
||||
|
@ -69,6 +69,11 @@ public:
|
||||
std::string shiftLeftFunction(size_t _numBits);
|
||||
std::string shiftRightFunction(size_t _numBits);
|
||||
|
||||
/// @returns the name of a function f(value, toInsert) -> newValue which replaces the
|
||||
/// _numBytes bytes starting at byte position _shiftBytes (counted from the least significant
|
||||
/// byte) by the _numBytes least significant bytes of `toInsert`.
|
||||
std::string updateByteSliceFunction(size_t _numBytes, size_t _shiftBytes);
|
||||
|
||||
/// @returns the name of a function that rounds its input to the next multiple
|
||||
/// of 32 or the input if it is a multiple of 32.
|
||||
std::string roundUpFunction();
|
||||
@ -110,6 +115,12 @@ public:
|
||||
/// single variable.
|
||||
std::string cleanupFromStorageFunction(Type const& _type, bool _splitFunctionTypes);
|
||||
|
||||
/// @returns the name of a function that prepares a value of the given type
|
||||
/// for being stored in storage. This usually includes cleanup and right-alignment
|
||||
/// to fit the number of bytes in storage.
|
||||
/// The resulting value might still have dirty higher order bits.
|
||||
std::string prepareStoreFunction(Type const& _type);
|
||||
|
||||
/// @returns the name of a function that allocates memory.
|
||||
/// Modifies the "free memory pointer"
|
||||
/// Arguments: size
|
||||
|
@ -39,7 +39,7 @@ string IRGenerationContext::addLocalVariable(VariableDeclaration const& _varDecl
|
||||
return m_localVariables[&_varDecl] = "vloc_" + _varDecl.name() + "_" + to_string(_varDecl.id());
|
||||
}
|
||||
|
||||
string IRGenerationContext::variableName(VariableDeclaration const& _varDecl)
|
||||
string IRGenerationContext::localVariableName(VariableDeclaration const& _varDecl)
|
||||
{
|
||||
solAssert(
|
||||
m_localVariables.count(&_varDecl),
|
||||
@ -48,6 +48,15 @@ string IRGenerationContext::variableName(VariableDeclaration const& _varDecl)
|
||||
return m_localVariables[&_varDecl];
|
||||
}
|
||||
|
||||
void IRGenerationContext::addStateVariable(
|
||||
VariableDeclaration const& _declaration,
|
||||
u256 _storageOffset,
|
||||
unsigned _byteOffset
|
||||
)
|
||||
{
|
||||
m_stateVariables[&_declaration] = make_pair(move(_storageOffset), _byteOffset);
|
||||
}
|
||||
|
||||
string IRGenerationContext::functionName(FunctionDefinition const& _function)
|
||||
{
|
||||
// @TODO previously, we had to distinguish creation context and runtime context,
|
||||
@ -128,3 +137,8 @@ string IRGenerationContext::internalDispatch(size_t _in, size_t _out)
|
||||
return templ.render();
|
||||
});
|
||||
}
|
||||
|
||||
YulUtilFunctions IRGenerationContext::utils()
|
||||
{
|
||||
return YulUtilFunctions(m_evmVersion, m_functions);
|
||||
}
|
||||
|
@ -26,6 +26,8 @@
|
||||
|
||||
#include <liblangutil/EVMVersion.h>
|
||||
|
||||
#include <libdevcore/Common.h>
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
@ -39,6 +41,7 @@ class ContractDefinition;
|
||||
class VariableDeclaration;
|
||||
class FunctionDefinition;
|
||||
class Expression;
|
||||
class YulUtilFunctions;
|
||||
|
||||
/**
|
||||
* Class that contains contextual information during IR generation.
|
||||
@ -62,7 +65,16 @@ public:
|
||||
|
||||
|
||||
std::string addLocalVariable(VariableDeclaration const& _varDecl);
|
||||
std::string variableName(VariableDeclaration const& _varDecl);
|
||||
bool isLocalVariable(VariableDeclaration const& _varDecl) const { return m_localVariables.count(&_varDecl); }
|
||||
std::string localVariableName(VariableDeclaration const& _varDecl);
|
||||
|
||||
void addStateVariable(VariableDeclaration const& _varDecl, u256 _storageOffset, unsigned _byteOffset);
|
||||
bool isStateVariable(VariableDeclaration const& _varDecl) const { return m_stateVariables.count(&_varDecl); }
|
||||
std::pair<u256, unsigned> storageLocationOfVariable(VariableDeclaration const& _varDecl) const
|
||||
{
|
||||
return m_stateVariables.at(&_varDecl);
|
||||
}
|
||||
|
||||
std::string functionName(FunctionDefinition const& _function);
|
||||
FunctionDefinition const& virtualFunction(FunctionDefinition const& _functionDeclaration);
|
||||
std::string virtualFunctionName(FunctionDefinition const& _functionDeclaration);
|
||||
@ -74,11 +86,16 @@ public:
|
||||
|
||||
std::string internalDispatch(size_t _in, size_t _out);
|
||||
|
||||
/// @returns a new copy of the utility function generator (but using the same function set).
|
||||
YulUtilFunctions utils();
|
||||
|
||||
private:
|
||||
langutil::EVMVersion m_evmVersion;
|
||||
OptimiserSettings m_optimiserSettings;
|
||||
std::vector<ContractDefinition const*> m_inheritanceHierarchy;
|
||||
std::map<VariableDeclaration const*, std::string> m_localVariables;
|
||||
/// Storage offsets of state variables
|
||||
std::map<VariableDeclaration const*, std::pair<u256, unsigned>> m_stateVariables;
|
||||
std::shared_ptr<MultiUseYulFunctionCollector> m_functions;
|
||||
size_t m_varCounter = 0;
|
||||
};
|
||||
|
@ -89,15 +89,14 @@ string IRGenerator::generate(ContractDefinition const& _contract)
|
||||
}
|
||||
)");
|
||||
|
||||
resetContext();
|
||||
m_context.setInheritanceHierarchy(_contract.annotation().linearizedBaseContracts);
|
||||
resetContext(_contract);
|
||||
t("CreationObject", creationObjectName(_contract));
|
||||
t("memoryInit", memoryInit());
|
||||
t("constructor", _contract.constructor() ? constructorCode(*_contract.constructor()) : "");
|
||||
t("deploy", deployCode(_contract));
|
||||
t("functions", m_context.functionCollector()->requestedFunctions());
|
||||
|
||||
resetContext();
|
||||
resetContext(_contract);
|
||||
m_context.setInheritanceHierarchy(_contract.annotation().linearizedBaseContracts);
|
||||
t("RuntimeObject", runtimeObjectName(_contract));
|
||||
t("dispatch", dispatchRoutine(_contract));
|
||||
@ -249,7 +248,7 @@ string IRGenerator::memoryInit()
|
||||
.render();
|
||||
}
|
||||
|
||||
void IRGenerator::resetContext()
|
||||
void IRGenerator::resetContext(ContractDefinition const& _contract)
|
||||
{
|
||||
solAssert(
|
||||
m_context.functionCollector()->requestedFunctions().empty(),
|
||||
@ -257,4 +256,8 @@ void IRGenerator::resetContext()
|
||||
);
|
||||
m_context = IRGenerationContext(m_evmVersion, m_optimiserSettings);
|
||||
m_utils = YulUtilFunctions(m_evmVersion, m_context.functionCollector());
|
||||
|
||||
m_context.setInheritanceHierarchy(_contract.annotation().linearizedBaseContracts);
|
||||
for (auto const& var: ContractType(_contract).stateVariables())
|
||||
m_context.addStateVariable(*get<0>(var), get<1>(var), get<2>(var));
|
||||
}
|
||||
|
@ -68,7 +68,7 @@ private:
|
||||
|
||||
std::string memoryInit();
|
||||
|
||||
void resetContext();
|
||||
void resetContext(ContractDefinition const& _contract);
|
||||
|
||||
langutil::EVMVersion const m_evmVersion;
|
||||
OptimiserSettings const m_optimiserSettings;
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include <libsolidity/codegen/ir/IRGeneratorForStatements.h>
|
||||
|
||||
#include <libsolidity/codegen/ir/IRGenerationContext.h>
|
||||
#include <libsolidity/codegen/ir/IRLValue.h>
|
||||
#include <libsolidity/codegen/YulUtilFunctions.h>
|
||||
#include <libsolidity/ast/TypeProvider.h>
|
||||
|
||||
@ -66,7 +67,7 @@ struct CopyTranslate: public yul::ASTCopier
|
||||
|
||||
return yul::Identifier{
|
||||
_identifier.location,
|
||||
yul::YulString{m_context.variableName(*varDecl)}
|
||||
yul::YulString{m_context.localVariableName(*varDecl)}
|
||||
};
|
||||
}
|
||||
|
||||
@ -79,6 +80,12 @@ private:
|
||||
|
||||
|
||||
|
||||
string IRGeneratorForStatements::code() const
|
||||
{
|
||||
solAssert(!m_currentLValue, "LValue not reset!");
|
||||
return m_code.str();
|
||||
}
|
||||
|
||||
bool IRGeneratorForStatements::visit(VariableDeclarationStatement const& _varDeclStatement)
|
||||
{
|
||||
for (auto const& decl: _varDeclStatement.declarations())
|
||||
@ -94,7 +101,7 @@ bool IRGeneratorForStatements::visit(VariableDeclarationStatement const& _varDec
|
||||
VariableDeclaration const& varDecl = *_varDeclStatement.declarations().front();
|
||||
m_code <<
|
||||
"let " <<
|
||||
m_context.variableName(varDecl) <<
|
||||
m_context.localVariableName(varDecl) <<
|
||||
" := " <<
|
||||
expressionAsType(*expression, *varDecl.type()) <<
|
||||
"\n";
|
||||
@ -102,7 +109,7 @@ bool IRGeneratorForStatements::visit(VariableDeclarationStatement const& _varDec
|
||||
else
|
||||
for (auto const& decl: _varDeclStatement.declarations())
|
||||
if (decl)
|
||||
m_code << "let " << m_context.variableName(*decl) << "\n";
|
||||
m_code << "let " << m_context.localVariableName(*decl) << "\n";
|
||||
|
||||
return false;
|
||||
}
|
||||
@ -112,17 +119,18 @@ bool IRGeneratorForStatements::visit(Assignment const& _assignment)
|
||||
solUnimplementedAssert(_assignment.assignmentOperator() == Token::Assign, "");
|
||||
|
||||
_assignment.rightHandSide().accept(*this);
|
||||
Type const* intermediateType = _assignment.rightHandSide().annotation().type->closestTemporaryType(
|
||||
_assignment.leftHandSide().annotation().type
|
||||
);
|
||||
string intermediateValue = m_context.newYulVariable();
|
||||
m_code << "let " << intermediateValue << " := " << expressionAsType(_assignment.rightHandSide(), *intermediateType) << "\n";
|
||||
|
||||
// TODO proper lvalue handling
|
||||
auto const& lvalue = dynamic_cast<Identifier const&>(_assignment.leftHandSide());
|
||||
string varName = m_context.variableName(dynamic_cast<VariableDeclaration const&>(*lvalue.annotation().referencedDeclaration));
|
||||
_assignment.leftHandSide().accept(*this);
|
||||
solAssert(!!m_currentLValue, "LValue not retrieved.");
|
||||
m_currentLValue->storeValue(intermediateValue, *intermediateType);
|
||||
m_currentLValue.reset();
|
||||
|
||||
m_code <<
|
||||
varName <<
|
||||
" := " <<
|
||||
expressionAsType(_assignment.rightHandSide(), *lvalue.annotation().type) <<
|
||||
"\n";
|
||||
defineExpression(_assignment) << varName << "\n";
|
||||
defineExpression(_assignment) << intermediateValue << "\n";
|
||||
|
||||
return false;
|
||||
}
|
||||
@ -179,7 +187,7 @@ bool IRGeneratorForStatements::visit(Return const& _return)
|
||||
// TODO support tuples
|
||||
solUnimplementedAssert(types.size() == 1, "Multi-returns not implemented.");
|
||||
m_code <<
|
||||
m_context.variableName(*returnParameters.front()) <<
|
||||
m_context.localVariableName(*returnParameters.front()) <<
|
||||
" := " <<
|
||||
expressionAsType(*value, *types.front()) <<
|
||||
"\n";
|
||||
@ -329,14 +337,26 @@ bool IRGeneratorForStatements::visit(InlineAssembly const& _inlineAsm)
|
||||
bool IRGeneratorForStatements::visit(Identifier const& _identifier)
|
||||
{
|
||||
Declaration const* declaration = _identifier.annotation().referencedDeclaration;
|
||||
string value;
|
||||
if (FunctionDefinition const* functionDef = dynamic_cast<FunctionDefinition const*>(declaration))
|
||||
value = to_string(m_context.virtualFunction(*functionDef).id());
|
||||
defineExpression(_identifier) << to_string(m_context.virtualFunction(*functionDef).id()) << "\n";
|
||||
else if (VariableDeclaration const* varDecl = dynamic_cast<VariableDeclaration const*>(declaration))
|
||||
value = m_context.variableName(*varDecl);
|
||||
{
|
||||
// TODO for the constant case, we have to be careful:
|
||||
// If the value is visited twice, `defineExpression` is called twice on
|
||||
// the same expression.
|
||||
solUnimplementedAssert(!varDecl->isConstant(), "");
|
||||
unique_ptr<IRLValue> lvalue;
|
||||
if (m_context.isLocalVariable(*varDecl))
|
||||
lvalue = make_unique<IRLocalVariable>(m_code, m_context, *varDecl);
|
||||
else if (m_context.isStateVariable(*varDecl))
|
||||
lvalue = make_unique<IRStorageItem>(m_code, m_context, *varDecl);
|
||||
else
|
||||
solAssert(false, "Invalid variable kind.");
|
||||
|
||||
setLValue(_identifier, move(lvalue));
|
||||
}
|
||||
else
|
||||
solUnimplemented("");
|
||||
defineExpression(_identifier) << value << "\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -375,3 +395,14 @@ ostream& IRGeneratorForStatements::defineExpression(Expression const& _expressio
|
||||
{
|
||||
return m_code << "let " << m_context.variable(_expression) << " := ";
|
||||
}
|
||||
|
||||
void IRGeneratorForStatements::setLValue(Expression const& _expression, unique_ptr<IRLValue> _lvalue)
|
||||
{
|
||||
solAssert(!m_currentLValue, "");
|
||||
|
||||
if (_expression.annotation().lValueRequested)
|
||||
// Do not define the expression, so it cannot be used as value.
|
||||
m_currentLValue = std::move(_lvalue);
|
||||
else
|
||||
defineExpression(_expression) << _lvalue->retrieveValue() << "\n";
|
||||
}
|
||||
|
@ -21,6 +21,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <libsolidity/ast/ASTVisitor.h>
|
||||
#include <libsolidity/codegen/ir/IRLValue.h>
|
||||
|
||||
namespace dev
|
||||
{
|
||||
@ -42,7 +43,7 @@ public:
|
||||
m_utils(_utils)
|
||||
{}
|
||||
|
||||
std::string code() const { return m_code.str(); }
|
||||
std::string code() const;
|
||||
|
||||
bool visit(VariableDeclarationStatement const& _variableDeclaration) override;
|
||||
bool visit(Assignment const& _assignment) override;
|
||||
@ -62,9 +63,12 @@ private:
|
||||
std::string expressionAsType(Expression const& _expression, Type const& _to);
|
||||
std::ostream& defineExpression(Expression const& _expression);
|
||||
|
||||
void setLValue(Expression const& _expression, std::unique_ptr<IRLValue> _lvalue);
|
||||
|
||||
std::ostringstream m_code;
|
||||
IRGenerationContext& m_context;
|
||||
YulUtilFunctions& m_utils;
|
||||
std::unique_ptr<IRLValue> m_currentLValue;
|
||||
};
|
||||
|
||||
}
|
||||
|
103
libsolidity/codegen/ir/IRLValue.cpp
Normal file
103
libsolidity/codegen/ir/IRLValue.cpp
Normal file
@ -0,0 +1,103 @@
|
||||
/*
|
||||
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/ast/AST.h>
|
||||
|
||||
#include <libdevcore/Whiskers.h>
|
||||
|
||||
using namespace std;
|
||||
using namespace dev;
|
||||
using namespace dev::solidity;
|
||||
|
||||
IRLocalVariable::IRLocalVariable(
|
||||
ostream& _code,
|
||||
IRGenerationContext& _context,
|
||||
VariableDeclaration const& _varDecl
|
||||
):
|
||||
IRLValue(_code, _context, _varDecl.annotation().type),
|
||||
m_variableName(_context.localVariableName(_varDecl))
|
||||
{
|
||||
}
|
||||
|
||||
void IRLocalVariable::storeValue(string const& _value, Type const& _type) const
|
||||
{
|
||||
solAssert(_type == *m_type, "Storing different types - not necessarily a problem.");
|
||||
m_code << m_variableName << " := " << _value << "\n";
|
||||
}
|
||||
|
||||
IRStorageItem::IRStorageItem(
|
||||
ostream& _code,
|
||||
IRGenerationContext& _context,
|
||||
VariableDeclaration const& _varDecl
|
||||
):
|
||||
IRLValue(_code, _context, _varDecl.annotation().type)
|
||||
{
|
||||
u256 slot;
|
||||
unsigned offset;
|
||||
std::tie(slot, offset) = _context.storageLocationOfVariable(_varDecl);
|
||||
m_slot = toCompactHexWithPrefix(slot);
|
||||
m_offset = offset;
|
||||
}
|
||||
|
||||
string IRStorageItem::retrieveValue() const
|
||||
{
|
||||
if (!m_type->isValueType())
|
||||
return m_slot;
|
||||
solUnimplementedAssert(m_type->category() != Type::Category::Function, "");
|
||||
return m_context.utils().readFromStorage(*m_type, m_offset, false) + "(" + m_slot + ")";
|
||||
}
|
||||
|
||||
void IRStorageItem::storeValue(string const& _value, Type const& _sourceType) const
|
||||
{
|
||||
if (m_type->isValueType())
|
||||
{
|
||||
solAssert(m_type->storageBytes() <= 32, "Invalid storage bytes size.");
|
||||
solAssert(m_type->storageBytes() > 0, "Invalid storage bytes size.");
|
||||
solAssert(m_type->storageBytes() + m_offset <= 32, "");
|
||||
|
||||
solAssert(_sourceType == *m_type, "Different type, but might not be an error.");
|
||||
|
||||
m_code <<
|
||||
Whiskers("sstore(<slot>, <update>(sload(<slot>), <prepare>(<value>)))\n")
|
||||
("slot", m_slot)
|
||||
("update", m_context.utils().updateByteSliceFunction(m_type->storageBytes(), m_offset))
|
||||
("prepare", m_context.utils().prepareStoreFunction(*m_type))
|
||||
("value", _value)
|
||||
.render();
|
||||
}
|
||||
else
|
||||
{
|
||||
solAssert(
|
||||
_sourceType.category() == m_type->category(),
|
||||
"Wrong type conversation for assignment."
|
||||
);
|
||||
if (m_type->category() == Type::Category::Array)
|
||||
solUnimplementedAssert(false, "");
|
||||
else if (m_type->category() == Type::Category::Struct)
|
||||
solUnimplementedAssert(false, "");
|
||||
else
|
||||
solAssert(false, "Invalid non-value type for assignment.");
|
||||
}
|
||||
}
|
||||
|
95
libsolidity/codegen/ir/IRLValue.h
Normal file
95
libsolidity/codegen/ir/IRLValue.h
Normal file
@ -0,0 +1,95 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <ostream>
|
||||
|
||||
namespace dev
|
||||
{
|
||||
namespace solidity
|
||||
{
|
||||
|
||||
class VariableDeclaration;
|
||||
class IRGenerationContext;
|
||||
class Type;
|
||||
|
||||
/**
|
||||
* Abstract class used to retrieve, delete and store data in LValues.
|
||||
*/
|
||||
class IRLValue
|
||||
{
|
||||
protected:
|
||||
IRLValue(std::ostream& _code, IRGenerationContext& _context, Type const* _type = nullptr):
|
||||
m_code(_code),
|
||||
m_context(_context),
|
||||
m_type(_type)
|
||||
{}
|
||||
|
||||
public:
|
||||
virtual ~IRLValue() = default;
|
||||
/// @returns an expression to retrieve the value of the lvalue. This might also emit
|
||||
/// code to m_code.
|
||||
virtual std::string retrieveValue() const = 0;
|
||||
/// Appends code to m_code to store the value of @a _value (should be an identifier)
|
||||
/// of type @a _type in the lvalue. Might perform type conversion.
|
||||
virtual void storeValue(std::string const& _value, Type const& _type) const = 0;
|
||||
|
||||
protected:
|
||||
std::ostream& m_code;
|
||||
IRGenerationContext& m_context;
|
||||
Type const* m_type;
|
||||
};
|
||||
|
||||
class IRLocalVariable: public IRLValue
|
||||
{
|
||||
public:
|
||||
IRLocalVariable(
|
||||
std::ostream& _code,
|
||||
IRGenerationContext& _context,
|
||||
VariableDeclaration const& _varDecl
|
||||
);
|
||||
std::string retrieveValue() const override { return m_variableName; }
|
||||
void storeValue(std::string const& _value, Type const& _type) const override;
|
||||
|
||||
private:
|
||||
std::string m_variableName;
|
||||
};
|
||||
|
||||
class IRStorageItem: public IRLValue
|
||||
{
|
||||
public:
|
||||
IRStorageItem(
|
||||
std::ostream& _code,
|
||||
IRGenerationContext& _context,
|
||||
VariableDeclaration const& _varDecl
|
||||
);
|
||||
std::string retrieveValue() const override;
|
||||
void storeValue(std::string const& _value, Type const& _type) const override;
|
||||
|
||||
private:
|
||||
std::string m_slot;
|
||||
unsigned m_offset;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
contract C {
|
||||
uint16 x;
|
||||
byte y;
|
||||
uint16 z;
|
||||
function f(uint8 a) public returns (uint _x) {
|
||||
x = a;
|
||||
y = byte(uint8(x) + 1);
|
||||
z = uint8(y) + 1;
|
||||
x = z + 1;
|
||||
_x = x;
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: true
|
||||
// ----
|
||||
// f(uint8): 6 -> 9
|
@ -0,0 +1,17 @@
|
||||
contract C {
|
||||
uint x;
|
||||
uint y;
|
||||
function setX(uint a) public returns (uint _x) {
|
||||
x = a;
|
||||
_x = x;
|
||||
}
|
||||
function setY(uint a) public returns (uint _y) {
|
||||
y = a;
|
||||
_y = y;
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: true
|
||||
// ----
|
||||
// setX(uint256): 6 -> 6
|
||||
// setY(uint256): 2 -> 2
|
Loading…
Reference in New Issue
Block a user