Slightly improved IR codegen.

This commit is contained in:
Daniel Kirchner 2022-06-08 20:00:23 +02:00
parent fd83c278cd
commit 6c3d944bee
4 changed files with 50 additions and 23 deletions

View File

@ -1624,29 +1624,19 @@ string YulUtilFunctions::storageArrayPushZeroFunction(ArrayType const& _type)
{
solAssert(_type.location() == DataLocation::Storage, "");
solAssert(_type.isDynamicallySized(), "");
solAssert(!_type.isByteArrayOrString(), "");
solUnimplementedAssert(_type.baseType()->storageBytes() <= 32, "Base type is not yet implemented.");
string functionName = "array_push_zero_" + _type.identifier();
return m_functionCollector.createFunction(functionName, [&]() {
return Whiskers(R"(
function <functionName>(array) -> slot, offset {
<?isBytes>
let data := sload(array)
let oldLen := <extractLength>(data)
<increaseBytesSize>(array, data, oldLen, add(oldLen, 1))
slot := array
offset := oldLen
<!isBytes>
let oldLen := <fetchLength>(array)
if iszero(lt(oldLen, <maxArrayLength>)) { <panic>() }
sstore(array, add(oldLen, 1))
slot, offset := <indexAccess>(array, oldLen)
</isBytes>
let oldLen := <fetchLength>(array)
if iszero(lt(oldLen, <maxArrayLength>)) { <panic>() }
sstore(array, add(oldLen, 1))
slot, offset := <indexAccess>(array, oldLen)
})")
("functionName", functionName)
("isBytes", _type.isByteArrayOrString())
("increaseBytesSize", _type.isByteArrayOrString() ? increaseByteArraySizeFunction(_type) : "")
("extractLength", _type.isByteArrayOrString() ? extractByteArrayLengthFunction() : "")
("panic", panicFunction(PanicCode::ResourceError))
("fetchLength", arrayLengthFunction(_type))
("indexAccess", storageArrayIndexAccessFunction(_type))
@ -1655,6 +1645,28 @@ string YulUtilFunctions::storageArrayPushZeroFunction(ArrayType const& _type)
});
}
string YulUtilFunctions::storageBytesArrayPushZeroFunction(ArrayType const& _type)
{
solAssert(_type.location() == DataLocation::Storage, "");
solAssert(_type.isDynamicallySized(), "");
solAssert(_type.isByteArrayOrString(), "");
string functionName = "byte_array_push_zero_" + _type.identifier();
return m_functionCollector.createFunction(functionName, [&]() {
return Whiskers(R"(
function <functionName>(array) -> oldLen {
let data := sload(array)
oldLen := <extractLength>(data)
<increaseBytesSize>(array, data, oldLen, add(oldLen, 1))
})")
("functionName", functionName)
("increaseBytesSize", _type.isByteArrayOrString() ? increaseByteArraySizeFunction(_type) : "")
("extractLength", _type.isByteArrayOrString() ? extractByteArrayLengthFunction() : "")
.render();
});
}
string YulUtilFunctions::partialClearStorageSlotFunction()
{
string functionName = "partial_clear_storage_slot";

View File

@ -238,9 +238,15 @@ public:
std::string storageArrayPushFunction(ArrayType const& _type, Type const* _fromType = nullptr);
/// @returns the name of a function that pushes the base type's zero element to a storage array and returns storage slot and offset of the added element.
/// Cannot be used for bytes arrays.
/// signature: (array) -> slot, offset
std::string storageArrayPushZeroFunction(ArrayType const& _type);
/// @returns the name of a function that pushes the base type's zero element to a storage bytes array and returns the old length of the array.
/// Can only used for bytes arrays.
/// signature: (array) -> oldLength
std::string storageBytesArrayPushZeroFunction(ArrayType const& _type);
/// @returns the name of a function that will clear the storage area given
/// by the start and end (exclusive) parameters (slots).
/// signature: (start, end)

View File

@ -1372,20 +1372,28 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
if (arguments.empty())
{
auto slotName = m_context.newYulVariable();
auto offsetName = m_context.newYulVariable();
appendCode() << "let " << slotName << ", " << offsetName << " := " <<
m_utils.storageArrayPushZeroFunction(*arrayType) <<
"(" << IRVariable(_functionCall.expression()).commaSeparatedList() << ")\n";
if (arrayType->isByteArrayOrString())
{
string arraySlot = IRVariable(_functionCall.expression()).commaSeparatedList();
string oldLength = m_context.newYulVariable();
appendCode() << "let " << oldLength << " := " <<
m_utils.storageBytesArrayPushZeroFunction(*arrayType) <<
"(" << arraySlot << ")\n";
setLValue(_functionCall, IRLValue{
*arrayType->baseType(),
IRLValue::StorageBytesElement{
slotName,
offsetName
arraySlot,
oldLength
}
});
}
else
{
auto slotName = m_context.newYulVariable();
auto offsetName = m_context.newYulVariable();
appendCode() << "let " << slotName << ", " << offsetName << " := " <<
m_utils.storageArrayPushZeroFunction(*arrayType) <<
"(" << IRVariable(_functionCall.expression()).commaSeparatedList() << ")\n";
setLValue(_functionCall, IRLValue{
*arrayType->baseType(),
IRLValue::Storage{
@ -1393,6 +1401,7 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
offsetName,
}
});
}
}
else
{

View File

@ -21,7 +21,7 @@ contract C {
// ----
// l() -> 0
// g(uint256): 70 ->
// gas irOptimized: 187549
// gas irOptimized: 185608
// gas legacy: 200625
// gas legacyOptimized: 195542
// l() -> 70