Merge pull request #9652 from ethereum/iceInlineAssemblyOffset

[Sol->Yul] Enabling storage pointers to local vars in inline assembly.
This commit is contained in:
chriseth 2020-08-26 17:12:54 +02:00 committed by GitHub
commit dbe0518cd2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 63 additions and 17 deletions

View File

@ -98,8 +98,9 @@ public:
void addStateVariable(VariableDeclaration const& _varDecl, u256 _storageOffset, unsigned _byteOffset); void addStateVariable(VariableDeclaration const& _varDecl, u256 _storageOffset, unsigned _byteOffset);
bool isStateVariable(VariableDeclaration const& _varDecl) const { return m_stateVariables.count(&_varDecl); } bool isStateVariable(VariableDeclaration const& _varDecl) const { return m_stateVariables.count(&_varDecl); }
std::pair<u256, unsigned> storageLocationOfVariable(VariableDeclaration const& _varDecl) const std::pair<u256, unsigned> storageLocationOfStateVariable(VariableDeclaration const& _varDecl) const
{ {
solAssert(isStateVariable(_varDecl), "");
return m_stateVariables.at(&_varDecl); return m_stateVariables.at(&_varDecl);
} }

View File

@ -305,7 +305,7 @@ string IRGenerator::generateGetter(VariableDeclaration const& _varDecl)
string code; string code;
auto const& location = m_context.storageLocationOfVariable(_varDecl); auto const& location = m_context.storageLocationOfStateVariable(_varDecl);
code += Whiskers(R"( code += Whiskers(R"(
let slot := <slot> let slot := <slot>
let offset := <offset> let offset := <offset>

View File

@ -75,18 +75,30 @@ struct CopyTranslate: public yul::ASTCopier
{ {
solAssert(reference.isOffset != reference.isSlot, ""); solAssert(reference.isOffset != reference.isSlot, "");
pair<u256, unsigned> slot_offset = m_context.storageLocationOfVariable(*varDecl); string value;
if (varDecl->isStateVariable())
value =
reference.isSlot ?
m_context.storageLocationOfStateVariable(*varDecl).first.str() :
to_string(m_context.storageLocationOfStateVariable(*varDecl).second);
else
{
solAssert(varDecl->isLocalVariable(), "");
if (reference.isSlot)
value = IRVariable{*varDecl}.part("slot").name();
else if (varDecl->type()->isValueType())
value = IRVariable{*varDecl}.part("offset").name();
else
{
solAssert(!IRVariable{*varDecl}.hasPart("offset"), "");
value = "0";
}
}
string const value = reference.isSlot ? if (isdigit(value.front()))
slot_offset.first.str() : return yul::Literal{_identifier.location, yul::LiteralKind::Number, yul::YulString{value}, {}};
to_string(slot_offset.second); else
return yul::Identifier{_identifier.location, yul::YulString{value}};
return yul::Literal{
_identifier.location,
yul::LiteralKind::Number,
yul::YulString{value},
{}
};
} }
} }
return ASTCopier::operator()(_identifier); return ASTCopier::operator()(_identifier);
@ -152,8 +164,8 @@ void IRGeneratorForStatements::initializeStateVar(VariableDeclaration const& _va
_varDecl.immutable() ? _varDecl.immutable() ?
IRLValue{*_varDecl.annotation().type, IRLValue::Immutable{&_varDecl}} : IRLValue{*_varDecl.annotation().type, IRLValue::Immutable{&_varDecl}} :
IRLValue{*_varDecl.annotation().type, IRLValue::Storage{ IRLValue{*_varDecl.annotation().type, IRLValue::Storage{
util::toCompactHexWithPrefix(m_context.storageLocationOfVariable(_varDecl).first), util::toCompactHexWithPrefix(m_context.storageLocationOfStateVariable(_varDecl).first),
m_context.storageLocationOfVariable(_varDecl).second m_context.storageLocationOfStateVariable(_varDecl).second
}}, }},
*_varDecl.value() *_varDecl.value()
); );
@ -2026,8 +2038,8 @@ void IRGeneratorForStatements::handleVariableReference(
setLValue(_referencingExpression, IRLValue{ setLValue(_referencingExpression, IRLValue{
*_variable.annotation().type, *_variable.annotation().type,
IRLValue::Storage{ IRLValue::Storage{
toCompactHexWithPrefix(m_context.storageLocationOfVariable(_variable).first), toCompactHexWithPrefix(m_context.storageLocationOfStateVariable(_variable).first),
m_context.storageLocationOfVariable(_variable).second m_context.storageLocationOfStateVariable(_variable).second
} }
}); });
else else

View File

@ -53,6 +53,17 @@ IRVariable IRVariable::part(string const& _name) const
solAssert(false, "Invalid stack item name: " + _name); solAssert(false, "Invalid stack item name: " + _name);
} }
bool IRVariable::hasPart(std::string const& _name) const
{
for (auto const& [itemName, itemType]: m_type.stackItems())
if (itemName == _name)
{
solAssert(itemName.empty() || itemType, "");
return true;
}
return false;
}
vector<string> IRVariable::stackSlots() const vector<string> IRVariable::stackSlots() const
{ {
vector<string> result; vector<string> result;

View File

@ -71,6 +71,10 @@ public:
/// in ``m_type.stackItems()`` and may again occupy multiple stack slots. /// in ``m_type.stackItems()`` and may again occupy multiple stack slots.
IRVariable part(std::string const& _slot) const; 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. /// @returns a vector containing the names of the stack slots of the variable.
std::vector<std::string> stackSlots() const; std::vector<std::string> stackSlots() const;

View File

@ -0,0 +1,18 @@
contract C {
uint256[] public a;
function f() public returns (uint256) {
uint256[] storage x = a;
uint256 off;
assembly {
sstore(x.slot, 7)
off := x.offset
}
assert(off == 0);
return a.length;
}
}
// ====
// compileViaYul: also
// ----
// f() -> 7