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 functionName = "mapping_index_access_" + _mappingType.identifier() + "_of_" + _keyType.identifier();
|
||||
|
@ -292,6 +292,10 @@ public:
|
||||
/// of the storage array into it.
|
||||
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.
|
||||
/// @param _mappingType the type of the mapping
|
||||
/// @param _keyType the type of the value provided
|
||||
|
@ -1325,7 +1325,19 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
|
||||
}
|
||||
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;
|
||||
}
|
||||
case FunctionType::Kind::MetaType:
|
||||
@ -1998,6 +2010,8 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess)
|
||||
}
|
||||
else if (EnumType const* enumType = dynamic_cast<EnumType const*>(&actualType))
|
||||
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
|
||||
// The old code generator had a generic "else" case here
|
||||
// without any specific code being generated,
|
||||
|
Loading…
Reference in New Issue
Block a user