Skip to content

Commit

Permalink
[Sol->Yul] Implementing bytes.concat in IR codegen.
Browse files Browse the repository at this point in the history
Co-authored-by: Daniel Kirchner <[email protected]>
  • Loading branch information
mijovic and ekpyron committed Mar 24, 2021
1 parent e7da9f3 commit 80866d3
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 1 deletion.
54 changes: 54 additions & 0 deletions libsolidity/codegen/YulUtilFunctions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
4 changes: 4 additions & 0 deletions libsolidity/codegen/YulUtilFunctions.h
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,10 @@ class YulUtilFunctions
/// 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
Expand Down
16 changes: 15 additions & 1 deletion libsolidity/codegen/ir/IRGeneratorForStatements.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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,
Expand Down

0 comments on commit 80866d3

Please sign in to comment.