mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Slightly improved IR codegen.
This commit is contained in:
parent
fd83c278cd
commit
6c3d944bee
@ -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";
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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
|
||||
{
|
||||
|
||||
@ -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
|
||||
|
||||
Loading…
Reference in New Issue
Block a user