mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
[Sol->Yul] Implementing bytes.concat in IR codegen.
Co-authored-by: Daniel Kirchner <daniel@ekpyron.org>
This commit is contained in:
parent
e7da9f3d52
commit
80866d3ee4
@ -2351,6 +2351,60 @@ string YulUtilFunctions::copyArrayFromStorageToMemoryFunction(ArrayType const& _
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
string YulUtilFunctions::bytesConcatFunction(vector<Type const*> const& _argumentTypes)
|
||||||
|
{
|
||||||
|
string functionName = "bytes_concat";
|
||||||
|
size_t totalParams = 0;
|
||||||
|
vector<Type const*> targetTypes;
|
||||||
|
for (Type const* argumentType: _argumentTypes)
|
||||||
|
{
|
||||||
|
solAssert(
|
||||||
|
argumentType->isImplicitlyConvertibleTo(*TypeProvider::bytesMemory()) ||
|
||||||
|
argumentType->isImplicitlyConvertibleTo(*TypeProvider::fixedBytes(32)),
|
||||||
|
""
|
||||||
|
);
|
||||||
|
if (argumentType->category() == Type::Category::FixedBytes)
|
||||||
|
targetTypes.emplace_back(argumentType);
|
||||||
|
else if (
|
||||||
|
auto const* literalType = dynamic_cast<StringLiteralType const*>(argumentType);
|
||||||
|
literalType && literalType->value().size() <= 32
|
||||||
|
)
|
||||||
|
targetTypes.emplace_back(TypeProvider::fixedBytes(static_cast<unsigned>(literalType->value().size())));
|
||||||
|
else
|
||||||
|
{
|
||||||
|
solAssert(argumentType->isImplicitlyConvertibleTo(*TypeProvider::bytesMemory()), "");
|
||||||
|
targetTypes.emplace_back(TypeProvider::bytesMemory());
|
||||||
|
}
|
||||||
|
|
||||||
|
totalParams += argumentType->sizeOnStack();
|
||||||
|
functionName += "_" + argumentType->identifier();
|
||||||
|
}
|
||||||
|
|
||||||
|
return m_functionCollector.createFunction(functionName, [&]() {
|
||||||
|
Whiskers templ(R"(
|
||||||
|
function <functionName>(<parameters>) -> outPtr {
|
||||||
|
outPtr := <allocateUnbounded>()
|
||||||
|
let dataStart := add(outPtr, 0x20)
|
||||||
|
let dataEnd := <encodePacked>(dataStart<?+parameters>, <parameters></+parameters>)
|
||||||
|
mstore(outPtr, sub(dataEnd, dataStart))
|
||||||
|
<finalizeAllocation>(outPtr, sub(dataEnd, outPtr))
|
||||||
|
}
|
||||||
|
)");
|
||||||
|
templ("functionName", functionName);
|
||||||
|
templ("parameters", suffixedVariableNameList("param_", 0, totalParams));
|
||||||
|
templ("allocateUnbounded", allocateUnboundedFunction());
|
||||||
|
templ("finalizeAllocation", finalizeAllocationFunction());
|
||||||
|
templ(
|
||||||
|
"encodePacked",
|
||||||
|
ABIFunctions{m_evmVersion, m_revertStrings, m_functionCollector}.tupleEncoderPacked(
|
||||||
|
_argumentTypes,
|
||||||
|
targetTypes
|
||||||
|
)
|
||||||
|
);
|
||||||
|
return templ.render();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
string YulUtilFunctions::mappingIndexAccessFunction(MappingType const& _mappingType, Type const& _keyType)
|
string YulUtilFunctions::mappingIndexAccessFunction(MappingType const& _mappingType, Type const& _keyType)
|
||||||
{
|
{
|
||||||
string functionName = "mapping_index_access_" + _mappingType.identifier() + "_of_" + _keyType.identifier();
|
string functionName = "mapping_index_access_" + _mappingType.identifier() + "_of_" + _keyType.identifier();
|
||||||
|
@ -292,6 +292,10 @@ public:
|
|||||||
/// of the storage array into it.
|
/// of the storage array into it.
|
||||||
std::string copyArrayFromStorageToMemoryFunction(ArrayType const& _from, ArrayType const& _to);
|
std::string copyArrayFromStorageToMemoryFunction(ArrayType const& _from, ArrayType const& _to);
|
||||||
|
|
||||||
|
/// @returns the name of a function that does concatenation of variadic number of bytes
|
||||||
|
/// or fixed bytes
|
||||||
|
std::string bytesConcatFunction(std::vector<Type const*> const& _argumentTypes);
|
||||||
|
|
||||||
/// @returns the name of a function that performs index access for mappings.
|
/// @returns the name of a function that performs index access for mappings.
|
||||||
/// @param _mappingType the type of the mapping
|
/// @param _mappingType the type of the mapping
|
||||||
/// @param _keyType the type of the value provided
|
/// @param _keyType the type of the value provided
|
||||||
|
@ -1325,7 +1325,19 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
|
|||||||
}
|
}
|
||||||
case FunctionType::Kind::BytesConcat:
|
case FunctionType::Kind::BytesConcat:
|
||||||
{
|
{
|
||||||
solUnimplementedAssert(false, "bytes.concat not yet implemented in codegen.");
|
TypePointers argumentTypes;
|
||||||
|
vector<string> argumentVars;
|
||||||
|
for (ASTPointer<Expression const> const& argument: arguments)
|
||||||
|
{
|
||||||
|
argumentTypes.emplace_back(&type(*argument));
|
||||||
|
argumentVars += IRVariable(*argument).stackSlots();
|
||||||
|
}
|
||||||
|
define(IRVariable(_functionCall)) <<
|
||||||
|
m_utils.bytesConcatFunction(argumentTypes) <<
|
||||||
|
"(" <<
|
||||||
|
joinHumanReadable(argumentVars) <<
|
||||||
|
")\n";
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case FunctionType::Kind::MetaType:
|
case FunctionType::Kind::MetaType:
|
||||||
@ -1998,6 +2010,8 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess)
|
|||||||
}
|
}
|
||||||
else if (EnumType const* enumType = dynamic_cast<EnumType const*>(&actualType))
|
else if (EnumType const* enumType = dynamic_cast<EnumType const*>(&actualType))
|
||||||
define(_memberAccess) << to_string(enumType->memberValue(_memberAccess.memberName())) << "\n";
|
define(_memberAccess) << to_string(enumType->memberValue(_memberAccess.memberName())) << "\n";
|
||||||
|
else if (auto const* arrayType = dynamic_cast<ArrayType const*>(&actualType))
|
||||||
|
solAssert(arrayType->isByteArray() && member == "concat", "");
|
||||||
else
|
else
|
||||||
// The old code generator had a generic "else" case here
|
// The old code generator had a generic "else" case here
|
||||||
// without any specific code being generated,
|
// without any specific code being generated,
|
||||||
|
Loading…
Reference in New Issue
Block a user