mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #10221 from ethereum/refactorArrayConversions
[Sol->Yul] Refactor array conversions
This commit is contained in:
commit
6cc264ff0a
@ -2714,8 +2714,7 @@ string YulUtilFunctions::conversionFunction(Type const& _from, Type const& _to)
|
|||||||
.render();
|
.render();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
else if (_from.category() == Type::Category::ArraySlice)
|
||||||
if (_from.category() == Type::Category::ArraySlice)
|
|
||||||
{
|
{
|
||||||
solAssert(_from.isDynamicallySized(), "");
|
solAssert(_from.isDynamicallySized(), "");
|
||||||
solAssert(_from.dataStoredIn(DataLocation::CallData), "");
|
solAssert(_from.dataStoredIn(DataLocation::CallData), "");
|
||||||
@ -2746,6 +2745,14 @@ string YulUtilFunctions::conversionFunction(Type const& _from, Type const& _to)
|
|||||||
.render();
|
.render();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
else if (_from.category() == Type::Category::Array)
|
||||||
|
{
|
||||||
|
solAssert(_to.category() == Type::Category::Array, "");
|
||||||
|
return arrayConversionFunction(
|
||||||
|
dynamic_cast<ArrayType const&>(_from),
|
||||||
|
dynamic_cast<ArrayType const&>(_to)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if (_from.sizeOnStack() != 1 || _to.sizeOnStack() != 1)
|
if (_from.sizeOnStack() != 1 || _to.sizeOnStack() != 1)
|
||||||
return conversionFunctionSpecial(_from, _to);
|
return conversionFunctionSpecial(_from, _to);
|
||||||
@ -2852,42 +2859,6 @@ string YulUtilFunctions::conversionFunction(Type const& _from, Type const& _to)
|
|||||||
case Type::Category::FixedPoint:
|
case Type::Category::FixedPoint:
|
||||||
solUnimplemented("Fixed point types not implemented.");
|
solUnimplemented("Fixed point types not implemented.");
|
||||||
break;
|
break;
|
||||||
case Type::Category::Array:
|
|
||||||
{
|
|
||||||
if (_from == _to)
|
|
||||||
body = "converted := value";
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ArrayType const& from = dynamic_cast<decltype(from)>(_from);
|
|
||||||
ArrayType const& to = dynamic_cast<decltype(to)>(_to);
|
|
||||||
|
|
||||||
switch (to.location())
|
|
||||||
{
|
|
||||||
case DataLocation::Storage:
|
|
||||||
// Other cases are done explicitly in LValue::storeValue, and only possible by assignment.
|
|
||||||
solAssert(
|
|
||||||
(to.isPointer() || (from.isByteArray() && to.isByteArray())) &&
|
|
||||||
from.location() == DataLocation::Storage,
|
|
||||||
"Invalid conversion to storage type."
|
|
||||||
);
|
|
||||||
body = "converted := value";
|
|
||||||
break;
|
|
||||||
case DataLocation::Memory:
|
|
||||||
// Copy the array to a free position in memory, unless it is already in memory.
|
|
||||||
if (from.location() == DataLocation::Memory)
|
|
||||||
body = "converted := value";
|
|
||||||
else if (from.location() == DataLocation::CallData)
|
|
||||||
solUnimplemented("Conversion of calldata types not yet implemented.");
|
|
||||||
else
|
|
||||||
body = "converted := " + copyArrayFromStorageToMemoryFunction(from, to) + "(value)";
|
|
||||||
break;
|
|
||||||
case DataLocation::CallData:
|
|
||||||
solUnimplemented("Conversion of calldata types not yet implemented.");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case Type::Category::Struct:
|
case Type::Category::Struct:
|
||||||
{
|
{
|
||||||
solAssert(toCategory == Type::Category::Struct, "");
|
solAssert(toCategory == Type::Category::Struct, "");
|
||||||
@ -2980,6 +2951,71 @@ string YulUtilFunctions::conversionFunction(Type const& _from, Type const& _to)
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
string YulUtilFunctions::arrayConversionFunction(ArrayType const& _from, ArrayType const& _to)
|
||||||
|
{
|
||||||
|
solUnimplementedAssert(_to.location() != DataLocation::CallData, "Conversion of calldata types not yet implemented.");
|
||||||
|
// Other cases are done explicitly in LValue::storeValue, and only possible by assignment.
|
||||||
|
if (_to.location() == DataLocation::Storage)
|
||||||
|
solAssert(
|
||||||
|
(_to.isPointer() || (_from.isByteArray() && _to.isByteArray())) &&
|
||||||
|
_from.location() == DataLocation::Storage,
|
||||||
|
"Invalid conversion to storage type."
|
||||||
|
);
|
||||||
|
if (_to.location() == DataLocation::Memory && _from.location() == DataLocation::CallData)
|
||||||
|
{
|
||||||
|
solUnimplementedAssert(_from.isDynamicallySized(), "");
|
||||||
|
solUnimplementedAssert(!_from.baseType()->isDynamicallyEncoded(), "");
|
||||||
|
solUnimplementedAssert(_from.isByteArray() && _to.isByteArray() && _to.isDynamicallySized(), "");
|
||||||
|
}
|
||||||
|
|
||||||
|
string functionName =
|
||||||
|
"convert_array_" +
|
||||||
|
_from.identifier() +
|
||||||
|
"_to_" +
|
||||||
|
_to.identifier();
|
||||||
|
|
||||||
|
return m_functionCollector.createFunction(functionName, [&]() {
|
||||||
|
Whiskers templ(R"(
|
||||||
|
function <functionName>(value<?fromCalldataDynamic>, length</fromCalldataDynamic>) -> converted {
|
||||||
|
<body>
|
||||||
|
}
|
||||||
|
)");
|
||||||
|
templ("functionName", functionName);
|
||||||
|
templ("fromCalldataDynamic", _from.dataStoredIn(DataLocation::CallData) && _from.isDynamicallySized());
|
||||||
|
|
||||||
|
if (
|
||||||
|
_from == _to ||
|
||||||
|
(_from.dataStoredIn(DataLocation::Memory) && _to.dataStoredIn(DataLocation::Memory)) ||
|
||||||
|
_to.dataStoredIn(DataLocation::Storage)
|
||||||
|
)
|
||||||
|
templ("body", "converted := value");
|
||||||
|
else if (_to.dataStoredIn(DataLocation::Memory))
|
||||||
|
templ(
|
||||||
|
"body",
|
||||||
|
Whiskers(R"(
|
||||||
|
// Copy the array to a free position in memory
|
||||||
|
<?fromStorage>
|
||||||
|
converted := <arrayStorageToMem>(value)
|
||||||
|
</fromStorage>
|
||||||
|
<?fromCalldata>
|
||||||
|
converted := <allocateMemoryArray>(length)
|
||||||
|
<copyToMemory>(value, add(converted, 0x20), length)
|
||||||
|
</fromCalldata>
|
||||||
|
)")
|
||||||
|
("fromStorage", _from.dataStoredIn(DataLocation::Storage))
|
||||||
|
("fromCalldata", _from.dataStoredIn(DataLocation::CallData))
|
||||||
|
("allocateMemoryArray", _from.dataStoredIn(DataLocation::CallData) ? allocateMemoryArrayFunction(_to) : "")
|
||||||
|
("copyToMemory", _from.dataStoredIn(DataLocation::CallData) ? copyToMemoryFunction(true) : "")
|
||||||
|
("arrayStorageToMem", _from.dataStoredIn(DataLocation::Storage) ? copyArrayFromStorageToMemoryFunction(_from, _to) : "")
|
||||||
|
.render()
|
||||||
|
);
|
||||||
|
else
|
||||||
|
solAssert(false, "");
|
||||||
|
|
||||||
|
return templ.render();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
string YulUtilFunctions::cleanupFunction(Type const& _type)
|
string YulUtilFunctions::cleanupFunction(Type const& _type)
|
||||||
{
|
{
|
||||||
string functionName = string("cleanup_") + _type.identifier();
|
string functionName = string("cleanup_") + _type.identifier();
|
||||||
@ -3434,29 +3470,6 @@ string YulUtilFunctions::conversionFunctionSpecial(Type const& _from, Type const
|
|||||||
.render();
|
.render();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_from.category() == Type::Category::Array && _to.category() == Type::Category::Array)
|
|
||||||
{
|
|
||||||
auto const& fromArrayType = dynamic_cast<ArrayType const&>(_from);
|
|
||||||
auto const& toArrayType = dynamic_cast<ArrayType const&>(_to);
|
|
||||||
|
|
||||||
solAssert(!fromArrayType.baseType()->isDynamicallyEncoded(), "");
|
|
||||||
solUnimplementedAssert(fromArrayType.isByteArray() && toArrayType.isByteArray(), "");
|
|
||||||
solUnimplementedAssert(toArrayType.location() == DataLocation::Memory, "");
|
|
||||||
solUnimplementedAssert(fromArrayType.location() == DataLocation::CallData, "");
|
|
||||||
solUnimplementedAssert(toArrayType.isDynamicallySized(), "");
|
|
||||||
|
|
||||||
Whiskers templ(R"(
|
|
||||||
function <functionName>(offset, length) -> converted {
|
|
||||||
converted := <allocateMemoryArray>(length)
|
|
||||||
<copyToMemory>(offset, add(converted, 0x20), length)
|
|
||||||
}
|
|
||||||
)");
|
|
||||||
templ("functionName", functionName);
|
|
||||||
templ("allocateMemoryArray", allocateMemoryArrayFunction(toArrayType));
|
|
||||||
templ("copyToMemory", copyToMemoryFunction(fromArrayType.location() == DataLocation::CallData));
|
|
||||||
return templ.render();
|
|
||||||
}
|
|
||||||
|
|
||||||
solUnimplementedAssert(
|
solUnimplementedAssert(
|
||||||
_from.category() == Type::Category::StringLiteral,
|
_from.category() == Type::Category::StringLiteral,
|
||||||
"Type conversion " + _from.toString() + " -> " + _to.toString() + " not yet implemented."
|
"Type conversion " + _from.toString() + " -> " + _to.toString() + " not yet implemented."
|
||||||
|
@ -421,6 +421,9 @@ public:
|
|||||||
);
|
);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
/// Special case of conversion functions - handles all array conversions.
|
||||||
|
std::string arrayConversionFunction(ArrayType const& _from, ArrayType const& _to);
|
||||||
|
|
||||||
/// Special case of conversionFunction - handles everything that does not
|
/// Special case of conversionFunction - handles everything that does not
|
||||||
/// use exactly one variable to hold the value.
|
/// use exactly one variable to hold the value.
|
||||||
std::string conversionFunctionSpecial(Type const& _from, Type const& _to);
|
std::string conversionFunctionSpecial(Type const& _from, Type const& _to);
|
||||||
|
@ -15,6 +15,6 @@ contract C {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ====
|
// ====
|
||||||
// compileViaYul: true
|
// compileViaYul: also
|
||||||
// ----
|
// ----
|
||||||
// f(uint32, (uint128, uint256[][2], uint32)): 55, 0x40, 77, 0x60, 88, 0x40, 0x40, 2, 1, 2 -> 55, 77, 1, 2, 88
|
// f(uint32, (uint128, uint256[][2], uint32)): 55, 0x40, 77, 0x60, 88, 0x40, 0x40, 2, 1, 2 -> 55, 77, 1, 2, 88
|
||||||
|
Loading…
Reference in New Issue
Block a user