Merge pull request #8949 from ethereum/sol-yul-refactor-add-arity

[Sol->Yul] Add Arity struct (refactor)
This commit is contained in:
chriseth 2020-05-19 23:58:39 +02:00 committed by GitHub
commit d7b434fc6b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 50 additions and 15 deletions

View File

@ -16,6 +16,7 @@
*/
#include <libsolidity/codegen/ir/Common.h>
#include <libsolidity/ast/TypeProvider.h>
#include <libsolutil/CommonIO.h>
@ -23,6 +24,13 @@ using namespace std;
using namespace solidity::util;
using namespace solidity::frontend;
YulArity YulArity::fromType(FunctionType const& _functionType)
{
return YulArity{
TupleType(_functionType.parameterTypes()).sizeOnStack(),
TupleType(_functionType.returnParameterTypes()).sizeOnStack()
};
}
string IRNames::function(FunctionDefinition const& _function)
{
// @TODO previously, we had to distinguish creation context and runtime context,

View File

@ -22,11 +22,28 @@
#include <libsolidity/ast/AST.h>
#include <algorithm>
#include <string>
namespace solidity::frontend
{
/**
* Structure that describes arity and co-arity of a Yul function, i.e. the number of its inputs and outputs.
*/
struct YulArity
{
explicit YulArity(size_t _in, size_t _out): in(_in), out(_out) {}
static YulArity fromType(FunctionType const& _functionType);
bool operator==(YulArity const& _other) const { return in == _other.in && out == _other.out; }
bool operator!=(YulArity const& _other) const { return !(*this == _other); }
size_t in; /// Number of input parameters
size_t out; /// Number of output parameters
};
struct IRNames
{
static std::string function(FunctionDefinition const& _function);
@ -45,3 +62,15 @@ struct IRNames
};
}
// Overloading std::less() makes it possible to use YulArity as a map key. We could define operator<
// instead but such an operator would be a bit ambiguous (e.g. YulArity{2, 2} would be be greater than
// YulArity{1, 10} in lexicographical order but the latter has greater total number of inputs and outputs).
template<>
struct std::less<solidity::frontend::YulArity>
{
bool operator() (solidity::frontend::YulArity const& _lhs, solidity::frontend::YulArity const& _rhs) const
{
return _lhs.in < _rhs.in || (_lhs.in == _rhs.in && _lhs.out < _rhs.out);
}
};

View File

@ -121,9 +121,9 @@ string IRGenerationContext::newYulVariable()
return "_" + to_string(++m_varCounter);
}
string IRGenerationContext::internalDispatch(size_t _in, size_t _out)
string IRGenerationContext::internalDispatch(YulArity const& _arity)
{
string funName = "dispatch_internal_in_" + to_string(_in) + "_out_" + to_string(_out);
string funName = "dispatch_internal_in_" + to_string(_arity.in) + "_out_" + to_string(_arity.out);
return m_functions.createFunction(funName, [&]() {
Whiskers templ(R"(
function <functionName>(fun <comma> <in>) <arrow> <out> {
@ -138,12 +138,12 @@ string IRGenerationContext::internalDispatch(size_t _in, size_t _out)
}
)");
templ("functionName", funName);
templ("comma", _in > 0 ? "," : "");
templ("comma", _arity.in > 0 ? "," : "");
YulUtilFunctions utils(m_evmVersion, m_revertStrings, m_functions);
templ("in", suffixedVariableNameList("in_", 0, _in));
templ("arrow", _out > 0 ? "->" : "");
templ("assignment_op", _out > 0 ? ":=" : "");
templ("out", suffixedVariableNameList("out_", 0, _out));
templ("in", suffixedVariableNameList("in_", 0, _arity.in));
templ("arrow", _arity.out > 0 ? "->" : "");
templ("assignment_op", _arity.out > 0 ? ":=" : "");
templ("out", suffixedVariableNameList("out_", 0, _arity.out));
// UNIMPLEMENTED: Internal library calls via pointers are not implemented yet.
// We're not generating code for internal library functions here even though it's possible
@ -153,10 +153,8 @@ string IRGenerationContext::internalDispatch(size_t _in, size_t _out)
for (auto const& contract: mostDerivedContract().annotation().linearizedBaseContracts)
for (FunctionDefinition const* function: contract->definedFunctions())
if (
FunctionType const* functionType = TypeProvider::function(*function, FunctionType::Kind::Internal);
!function->isConstructor() &&
TupleType(functionType->parameterTypes()).sizeOnStack() == _in &&
TupleType(functionType->returnParameterTypes()).sizeOnStack() == _out
YulArity::fromType(*TypeProvider::function(*function, FunctionType::Kind::Internal)) == _arity
)
{
// 0 is reserved for uninitialized function pointers

View File

@ -102,7 +102,7 @@ public:
std::string newYulVariable();
std::string internalDispatch(size_t _in, size_t _out);
std::string internalDispatch(YulArity const& _arity);
/// @returns a new copy of the utility function generator (but using the same function set).
YulUtilFunctions utils();

View File

@ -692,16 +692,16 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
joinHumanReadable(args) <<
")\n";
else
{
YulArity arity = YulArity::fromType(*functionType);
define(_functionCall) <<
// NOTE: internalDispatch() takes care of adding the function to function generation queue
m_context.internalDispatch(
TupleType(functionType->parameterTypes()).sizeOnStack(),
TupleType(functionType->returnParameterTypes()).sizeOnStack()
) <<
m_context.internalDispatch(arity) <<
"(" <<
IRVariable(_functionCall.expression()).part("functionIdentifier").name() <<
joinHumanReadablePrefixed(args) <<
")\n";
}
break;
}
case FunctionType::Kind::External: