[Sol->Yul] Implementing bytes to bytesNN for IR codegen.

Co-authored-by: Alex Beregszaszi <alex@rtfs.hu>
This commit is contained in:
Djordje Mijovic 2021-03-04 10:09:37 +01:00
parent ece42c07df
commit 52538558b1
3 changed files with 76 additions and 5 deletions

View File

@ -3084,8 +3084,13 @@ string YulUtilFunctions::conversionFunction(Type const& _from, Type const& _to)
}
else if (_from.category() == Type::Category::ArraySlice)
{
solAssert(_to.category() == Type::Category::Array, "");
auto const& fromType = dynamic_cast<ArraySliceType const&>(_from);
if (_to.category() == Type::Category::FixedBytes)
{
solAssert(fromType.arrayType().isByteArray(), "Array types other than bytes not convertible to bytesNN.");
return bytesToFixedBytesConversionFunction(fromType.arrayType(), dynamic_cast<FixedBytesType const &>(_to));
}
solAssert(_to.category() == Type::Category::Array, "");
auto const& targetType = dynamic_cast<ArrayType const&>(_to);
solAssert(fromType.arrayType().isImplicitlyConvertibleTo(targetType), "");
@ -3117,11 +3122,14 @@ string YulUtilFunctions::conversionFunction(Type const& _from, Type const& _to)
}
else if (_from.category() == Type::Category::Array)
{
auto const& fromArrayType = dynamic_cast<ArrayType const&>(_from);
if (_to.category() == Type::Category::FixedBytes)
{
solAssert(fromArrayType.isByteArray(), "Array types other than bytes not convertible to bytesNN.");
return bytesToFixedBytesConversionFunction(fromArrayType, dynamic_cast<FixedBytesType const &>(_to));
}
solAssert(_to.category() == Type::Category::Array, "");
return arrayConversionFunction(
dynamic_cast<ArrayType const&>(_from),
dynamic_cast<ArrayType const&>(_to)
);
return arrayConversionFunction(fromArrayType, dynamic_cast<ArrayType const&>(_to));
}
if (_from.sizeOnStack() != 1 || _to.sizeOnStack() != 1)
@ -3342,6 +3350,64 @@ string YulUtilFunctions::conversionFunction(Type const& _from, Type const& _to)
});
}
string YulUtilFunctions::bytesToFixedBytesConversionFunction(ArrayType const& _from, FixedBytesType const& _to)
{
solAssert(_from.isByteArray() && !_from.isString(), "");
solAssert(_from.isDynamicallySized(), "");
string functionName = "convert_bytes_to_fixedbytes_from_" + _from.identifier() + "_to_" + _to.identifier();
return m_functionCollector.createFunction(functionName, [&](auto& _args, auto& _returnParams) {
_args = { "array" };
bool fromCalldata = _from.dataStoredIn(DataLocation::CallData);
if (fromCalldata)
_args.emplace_back("len");
_returnParams = {"value"};
Whiskers templ(R"(
let length := <arrayLen>(array<?fromCalldata>, len</fromCalldata>)
let dataArea := array
<?fromMemory>
dataArea := <dataArea>(array)
</fromMemory>
<?fromStorage>
if gt(length, 31) { dataArea := <dataArea>(array) }
</fromStorage>
<?fromCalldata>
value := <cleanup>(calldataload(dataArea))
<!fromCalldata>
value := <extractValue>(dataArea)
</fromCalldata>
if lt(length, <fixedBytesLen>) {
value := and(
value,
<shl>(
mul(8, sub(<fixedBytesLen>, length)),
<mask>
)
)
}
)");
templ("fromCalldata", fromCalldata);
templ("arrayLen", arrayLengthFunction(_from));
templ("fixedBytesLen", to_string(_to.numBytes()));
templ("fromMemory", _from.dataStoredIn(DataLocation::Memory));
templ("fromStorage", _from.dataStoredIn(DataLocation::Storage));
templ("dataArea", arrayDataAreaFunction(_from));
if (fromCalldata)
templ("cleanup", cleanupFunction(_to));
else
templ(
"extractValue",
_from.dataStoredIn(DataLocation::Storage) ?
readFromStorage(_to, 32 - _to.numBytes(), false) :
readFromMemory(_to)
);
templ("shl", shiftLeftFunctionDynamic());
templ("mask", formatNumber(~((u256(1) << (256 - _to.numBytes() * 8)) - 1)));
return templ.render();
});
}
string YulUtilFunctions::copyStructToStorageFunction(StructType const& _from, StructType const& _to)
{
solAssert(_to.dataStoredIn(DataLocation::Storage), "");

View File

@ -411,6 +411,10 @@ public:
/// This is used for data being encoded or general type conversions in the code.
std::string conversionFunction(Type const& _from, Type const& _to);
/// @returns the name of a function that converts bytes array to fixed bytes type
/// signature: (array) -> value
std::string bytesToFixedBytesConversionFunction(ArrayType const& _from, FixedBytesType const& _to);
/// @returns the name of the cleanup function for the given type and
/// adds its implementation to the requested functions.
/// The cleanup function defers to the validator function with "assert"

View File

@ -30,6 +30,7 @@ enum class PanicCode
DivisionByZero = 0x12, // division or modulo by zero
EnumConversionError = 0x21, // enum conversion error
StorageEncodingError = 0x22, // invalid encoding in storage
FixedBytesConversionError = 0x23, // error converting to fixed bytes type
EmptyArrayPop = 0x31, // empty array pop
ArrayOutOfBounds = 0x32, // array out of bounds access
ResourceError = 0x41, // resource error (too large allocation or too large array)