From 6c3d944beedf4de6568865f329c2861bd2535a8c Mon Sep 17 00:00:00 2001 From: Daniel Kirchner Date: Wed, 8 Jun 2022 20:00:23 +0200 Subject: [PATCH] Slightly improved IR codegen. --- libsolidity/codegen/YulUtilFunctions.cpp | 42 ++++++++++++------- libsolidity/codegen/YulUtilFunctions.h | 6 +++ .../codegen/ir/IRGeneratorForStatements.cpp | 23 ++++++---- .../array/push/push_no_args_bytes.sol | 2 +- 4 files changed, 50 insertions(+), 23 deletions(-) diff --git a/libsolidity/codegen/YulUtilFunctions.cpp b/libsolidity/codegen/YulUtilFunctions.cpp index 27df2c32d..1a2ad3393 100644 --- a/libsolidity/codegen/YulUtilFunctions.cpp +++ b/libsolidity/codegen/YulUtilFunctions.cpp @@ -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 (array) -> slot, offset { - - let data := sload(array) - let oldLen := (data) - (array, data, oldLen, add(oldLen, 1)) - slot := array - offset := oldLen - - let oldLen := (array) - if iszero(lt(oldLen, )) { () } - sstore(array, add(oldLen, 1)) - slot, offset := (array, oldLen) - + let oldLen := (array) + if iszero(lt(oldLen, )) { () } + sstore(array, add(oldLen, 1)) + slot, offset := (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 (array) -> oldLen { + let data := sload(array) + oldLen := (data) + (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"; diff --git a/libsolidity/codegen/YulUtilFunctions.h b/libsolidity/codegen/YulUtilFunctions.h index 4d6e7efda..65cde1219 100644 --- a/libsolidity/codegen/YulUtilFunctions.h +++ b/libsolidity/codegen/YulUtilFunctions.h @@ -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) diff --git a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp index 68718e7cc..a5a7c600f 100644 --- a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp +++ b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp @@ -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 { diff --git a/test/libsolidity/semanticTests/array/push/push_no_args_bytes.sol b/test/libsolidity/semanticTests/array/push/push_no_args_bytes.sol index 85df2d890..d145bc25a 100644 --- a/test/libsolidity/semanticTests/array/push/push_no_args_bytes.sol +++ b/test/libsolidity/semanticTests/array/push/push_no_args_bytes.sol @@ -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