Use vector of slots.

This commit is contained in:
chriseth 2020-05-07 17:29:42 +02:00
parent 3212cb6caa
commit f38cf85482
11 changed files with 57 additions and 63 deletions

View File

@ -169,24 +169,24 @@ string IRGenerator::generateFunction(FunctionDefinition const& _function)
string functionName = m_context.functionName(_function); string functionName = m_context.functionName(_function);
return m_context.functionCollector().createFunction(functionName, [&]() { return m_context.functionCollector().createFunction(functionName, [&]() {
Whiskers t(R"( Whiskers t(R"(
function <functionName>(<params>) <returns> { function <functionName>(<params>)<?+retParams> -> <retParams></+retParams> {
<initReturnVariables> <initReturnVariables>
<body> <body>
} }
)"); )");
t("functionName", functionName); t("functionName", functionName);
string params; vector<string> params;
for (auto const& varDecl: _function.parameters()) for (auto const& varDecl: _function.parameters())
params += (params.empty() ? "" : ", ") + m_context.addLocalVariable(*varDecl).commaSeparatedList(); params += m_context.addLocalVariable(*varDecl).stackSlots();
t("params", params); t("params", joinHumanReadable(params));
string retParams; vector<string> retParams;
string retInit; string retInit;
for (auto const& varDecl: _function.returnParameters()) for (auto const& varDecl: _function.returnParameters())
{ {
retParams += (retParams.empty() ? "" : ", ") + m_context.addLocalVariable(*varDecl).commaSeparatedList(); retParams += m_context.addLocalVariable(*varDecl).stackSlots();
retInit += generateInitialAssignment(*varDecl); retInit += generateInitialAssignment(*varDecl);
} }
t("returns", retParams.empty() ? "" : " -> " + retParams); t("retParams", joinHumanReadable(retParams));
t("initReturnVariables", retInit); t("initReturnVariables", retInit);
t("body", generate(_function.body())); t("body", generate(_function.body()));
return t.render(); return t.render();
@ -300,11 +300,11 @@ string IRGenerator::generateInitialAssignment(VariableDeclaration const& _varDec
return generator.code(); return generator.code();
} }
pair<string, map<ContractDefinition const*, string>> IRGenerator::evaluateConstructorArguments( pair<string, map<ContractDefinition const*, vector<string>>> IRGenerator::evaluateConstructorArguments(
ContractDefinition const& _contract ContractDefinition const& _contract
) )
{ {
map<ContractDefinition const*, string> constructorParams; map<ContractDefinition const*, vector<string>> constructorParams;
vector<pair<ContractDefinition const*, std::vector<ASTPointer<Expression>>const *>> baseConstructorArguments; vector<pair<ContractDefinition const*, std::vector<ASTPointer<Expression>>const *>> baseConstructorArguments;
for (ASTPointer<InheritanceSpecifier> const& base: _contract.baseContracts()) for (ASTPointer<InheritanceSpecifier> const& base: _contract.baseContracts())
@ -338,11 +338,11 @@ pair<string, map<ContractDefinition const*, string>> IRGenerator::evaluateConstr
{ {
vector<string> params; vector<string> params;
for (size_t i = 0; i < arguments->size(); ++i) for (size_t i = 0; i < arguments->size(); ++i)
params.emplace_back(generator.evaluateExpression( params += generator.evaluateExpression(
*(arguments->at(i)), *(arguments->at(i)),
*(baseContract->constructor()->parameters()[i]->type()) *(baseContract->constructor()->parameters()[i]->type())
).commaSeparatedList()); ).stackSlots();
constructorParams[baseContract] = joinHumanReadable(params); constructorParams[baseContract] = std::move(params);
} }
} }
@ -363,16 +363,16 @@ string IRGenerator::initStateVariables(ContractDefinition const& _contract)
void IRGenerator::generateImplicitConstructors(ContractDefinition const& _contract) void IRGenerator::generateImplicitConstructors(ContractDefinition const& _contract)
{ {
auto listAllParams = [&]( auto listAllParams = [&](
map<ContractDefinition const*, string> const& baseParams) -> string map<ContractDefinition const*, vector<string>> const& baseParams) -> vector<string>
{ {
vector<string> params; vector<string> params;
for (ContractDefinition const* contract: _contract.annotation().linearizedBaseContracts) for (ContractDefinition const* contract: _contract.annotation().linearizedBaseContracts)
if (baseParams.count(contract)) if (baseParams.count(contract))
params.emplace_back(baseParams.at(contract)); params += baseParams.at(contract);
return joinHumanReadable(params); return params;
}; };
map<ContractDefinition const*, string> baseConstructorParams; map<ContractDefinition const*, vector<string>> baseConstructorParams;
for (size_t i = 0; i < _contract.annotation().linearizedBaseContracts.size(); ++i) for (size_t i = 0; i < _contract.annotation().linearizedBaseContracts.size(); ++i)
{ {
ContractDefinition const* contract = _contract.annotation().linearizedBaseContracts[i]; ContractDefinition const* contract = _contract.annotation().linearizedBaseContracts[i];
@ -387,16 +387,16 @@ void IRGenerator::generateImplicitConstructors(ContractDefinition const& _contra
<userDefinedConstructorBody> <userDefinedConstructorBody>
} }
)"); )");
string params; vector<string> params;
if (contract->constructor()) if (contract->constructor())
for (ASTPointer<VariableDeclaration> const& varDecl: contract->constructor()->parameters()) for (ASTPointer<VariableDeclaration> const& varDecl: contract->constructor()->parameters())
params += (params.empty() ? "" : ", ") + m_context.addLocalVariable(*varDecl).commaSeparatedList(); params += m_context.addLocalVariable(*varDecl).stackSlots();
t("params", params); t("params", joinHumanReadable(params));
string baseParamsString = listAllParams(baseConstructorParams); vector<string> baseParams = listAllParams(baseConstructorParams);
t("baseParams", baseParamsString); t("baseParams", joinHumanReadable(baseParams));
t("comma", !params.empty() && !baseParamsString.empty() ? ", " : ""); t("comma", !params.empty() && !baseParams.empty() ? ", " : "");
t("functionName", implicitConstructorName(*contract)); t("functionName", implicitConstructorName(*contract));
pair<string, map<ContractDefinition const*, string>> evaluatedArgs = evaluateConstructorArguments(*contract); pair<string, map<ContractDefinition const*, vector<string>>> evaluatedArgs = evaluateConstructorArguments(*contract);
baseConstructorParams.insert(evaluatedArgs.second.begin(), evaluatedArgs.second.end()); baseConstructorParams.insert(evaluatedArgs.second.begin(), evaluatedArgs.second.end());
t("evalBaseArguments", evaluatedArgs.first); t("evalBaseArguments", evaluatedArgs.first);
if (i < _contract.annotation().linearizedBaseContracts.size() - 1) if (i < _contract.annotation().linearizedBaseContracts.size() - 1)
@ -404,7 +404,7 @@ void IRGenerator::generateImplicitConstructors(ContractDefinition const& _contra
t("hasNextConstructor", true); t("hasNextConstructor", true);
ContractDefinition const* nextContract = _contract.annotation().linearizedBaseContracts[i + 1]; ContractDefinition const* nextContract = _contract.annotation().linearizedBaseContracts[i + 1];
t("nextConstructor", implicitConstructorName(*nextContract)); t("nextConstructor", implicitConstructorName(*nextContract));
t("nextParams", listAllParams(baseConstructorParams)); t("nextParams", joinHumanReadable(listAllParams(baseConstructorParams)));
} }
else else
t("hasNextConstructor", false); t("hasNextConstructor", false);

View File

@ -81,9 +81,8 @@ private:
/// Evaluates constructor's arguments for all base contracts (listed in inheritance specifiers) of /// Evaluates constructor's arguments for all base contracts (listed in inheritance specifiers) of
/// @a _contract /// @a _contract
/// @returns Pair of expressions needed to evaluate params and list of parameters in a map contract -> params /// @returns Pair of expressions needed to evaluate params and list of parameters in a map contract -> params
std::pair<std::string, std::map<ContractDefinition const*, std::string>> evaluateConstructorArguments( std::pair<std::string, std::map<ContractDefinition const*, std::vector<std::string>>>
ContractDefinition const& _contract evaluateConstructorArguments(ContractDefinition const& _contract);
);
/// Initializes state variables of /// Initializes state variables of
/// @a _contract /// @a _contract

View File

@ -637,13 +637,6 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
break; break;
case FunctionType::Kind::Internal: case FunctionType::Kind::Internal:
{ {
vector<string> args;
for (size_t i = 0; i < arguments.size(); ++i)
if (functionType->takesArbitraryParameters())
args.emplace_back(IRVariable(*arguments[i]).commaSeparatedList());
else
args.emplace_back(convert(*arguments[i], *parameterTypes[i]).commaSeparatedList());
optional<FunctionDefinition const*> functionDef; optional<FunctionDefinition const*> functionDef;
if (auto memberAccess = dynamic_cast<MemberAccess const*>(&_functionCall.expression())) if (auto memberAccess = dynamic_cast<MemberAccess const*>(&_functionCall.expression()))
{ {
@ -681,6 +674,13 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
solAssert(functionDef.has_value(), ""); solAssert(functionDef.has_value(), "");
solAssert(functionDef.value() == nullptr || functionDef.value()->isImplemented(), ""); solAssert(functionDef.value() == nullptr || functionDef.value()->isImplemented(), "");
vector<string> args;
for (size_t i = 0; i < arguments.size(); ++i)
if (functionType->takesArbitraryParameters())
args += IRVariable(*arguments[i]).stackSlots();
else
args += convert(*arguments[i], *parameterTypes[i]).stackSlots();
if (functionDef.value() != nullptr) if (functionDef.value() != nullptr)
define(_functionCall) << define(_functionCall) <<
m_context.enqueueFunctionForCodeGeneration(*functionDef.value()) << m_context.enqueueFunctionForCodeGeneration(*functionDef.value()) <<
@ -716,7 +716,7 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
ABIFunctions abi(m_context.evmVersion(), m_context.revertStrings(), m_context.functionCollector()); ABIFunctions abi(m_context.evmVersion(), m_context.revertStrings(), m_context.functionCollector());
vector<IRVariable> indexedArgs; vector<IRVariable> indexedArgs;
string nonIndexedArgs; vector<string> nonIndexedArgs;
TypePointers nonIndexedArgTypes; TypePointers nonIndexedArgTypes;
TypePointers nonIndexedParamTypes; TypePointers nonIndexedParamTypes;
if (!event.isAnonymous()) if (!event.isAnonymous())
@ -739,9 +739,7 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
} }
else else
{ {
string vars = IRVariable(arg).commaSeparatedList(); nonIndexedArgs += IRVariable(arg).stackSlots();
if (!vars.empty())
nonIndexedArgs += ", " + move(vars);
nonIndexedArgTypes.push_back(arg.annotation().type); nonIndexedArgTypes.push_back(arg.annotation().type);
nonIndexedParamTypes.push_back(paramTypes[i]); nonIndexedParamTypes.push_back(paramTypes[i]);
} }
@ -756,7 +754,7 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
templ("end", m_context.newYulVariable()); templ("end", m_context.newYulVariable());
templ("freeMemory", freeMemory()); templ("freeMemory", freeMemory());
templ("encode", abi.tupleEncoder(nonIndexedArgTypes, nonIndexedParamTypes)); templ("encode", abi.tupleEncoder(nonIndexedArgTypes, nonIndexedParamTypes));
templ("nonIndexedArgs", nonIndexedArgs); templ("nonIndexedArgs", joinHumanReadablePrefixed(nonIndexedArgs));
templ("log", "log" + to_string(indexedArgs.size())); templ("log", "log" + to_string(indexedArgs.size()));
templ("indexedArgs", joinHumanReadablePrefixed(indexedArgs | boost::adaptors::transformed([&](auto const& _arg) { templ("indexedArgs", joinHumanReadablePrefixed(indexedArgs | boost::adaptors::transformed([&](auto const& _arg) {
return _arg.commaSeparatedList(); return _arg.commaSeparatedList();
@ -813,8 +811,7 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
templ("allocateTemporary", m_utils.allocationTemporaryMemoryFunction()); templ("allocateTemporary", m_utils.allocationTemporaryMemoryFunction());
templ( templ(
"argumentVars", "argumentVars",
(type(*arguments.front()).sizeOnStack() > 0 ? ", " : "") + joinHumanReadablePrefixed(IRVariable{*arguments.front()}.stackSlots())
IRVariable{*arguments.front()}.commaSeparatedList()
); );
templ("encode", m_context.abiFunctions().tupleEncoder( templ("encode", m_context.abiFunctions().tupleEncoder(
{&type(*arguments.front())}, {&type(*arguments.front())},
@ -991,11 +988,11 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
); );
TypePointers argumentTypes; TypePointers argumentTypes;
string constructorParams; vector<string> constructorParams;
for (ASTPointer<Expression const> const& arg: arguments) for (ASTPointer<Expression const> const& arg: arguments)
{ {
argumentTypes.push_back(arg->annotation().type); argumentTypes.push_back(arg->annotation().type);
constructorParams += ", " + IRVariable{*arg}.commaSeparatedList(); constructorParams += IRVariable{*arg}.stackSlots();
} }
ContractDefinition const* contract = ContractDefinition const* contract =
@ -1023,7 +1020,7 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
t("abiEncode", t("abiEncode",
m_context.abiFunctions().tupleEncoder(argumentTypes, functionType->parameterTypes(), false) m_context.abiFunctions().tupleEncoder(argumentTypes, functionType->parameterTypes(), false)
); );
t("constructorParams", constructorParams); t("constructorParams", joinHumanReadablePrefixed(constructorParams));
t("value", functionType->valueSet() ? IRVariable(_functionCall.expression()).part("value").name() : "0"); t("value", functionType->valueSet() ? IRVariable(_functionCall.expression()).part("value").name() : "0");
t("saltSet", functionType->saltSet()); t("saltSet", functionType->saltSet());
if (functionType->saltSet()) if (functionType->saltSet())
@ -1398,14 +1395,11 @@ void IRGeneratorForStatements::endVisit(IndexAccess const& _indexAccess)
solAssert(keyType.sizeOnStack() <= 1, ""); solAssert(keyType.sizeOnStack() <= 1, "");
string slot = m_context.newYulVariable(); string slot = m_context.newYulVariable();
Whiskers templ("let <slot> := <indexAccess>(<base> <key>)\n"); Whiskers templ("let <slot> := <indexAccess>(<base><?+key>,<key></+key>)\n");
templ("slot", slot); templ("slot", slot);
templ("indexAccess", m_utils.mappingIndexAccessFunction(mappingType, keyType)); templ("indexAccess", m_utils.mappingIndexAccessFunction(mappingType, keyType));
templ("base", IRVariable(_indexAccess.baseExpression()).commaSeparatedList()); templ("base", IRVariable(_indexAccess.baseExpression()).commaSeparatedList());
if (keyType.sizeOnStack() == 0) templ("key", IRVariable(*_indexAccess.indexExpression()).commaSeparatedList());
templ("key", "");
else
templ("key", ", " + IRVariable(*_indexAccess.indexExpression()).commaSeparatedList());
m_code << templ.render(); m_code << templ.render();
setLValue(_indexAccess, IRLValue{ setLValue(_indexAccess, IRLValue{
*_indexAccess.annotation().type, *_indexAccess.annotation().type,
@ -1678,10 +1672,8 @@ void IRGeneratorForStatements::appendExternalFunctionCall(
for (auto const& arg: _arguments) for (auto const& arg: _arguments)
{ {
argumentTypes.emplace_back(&type(*arg)); argumentTypes.emplace_back(&type(*arg));
if (IRVariable(*arg).type().sizeOnStack() > 0) argumentStrings += IRVariable(*arg).stackSlots();
argumentStrings.emplace_back(IRVariable(*arg).commaSeparatedList());
} }
string argumentString = argumentStrings.empty() ? ""s : (", " + joinHumanReadable(argumentStrings));
solUnimplementedAssert(funKind != FunctionType::Kind::ECRecover, ""); solUnimplementedAssert(funKind != FunctionType::Kind::ECRecover, "");
@ -1796,7 +1788,7 @@ void IRGeneratorForStatements::appendExternalFunctionCall(
} }
else else
templ("encodeArgs", abi.tupleEncoder(argumentTypes, funType.parameterTypes(), encodeForLibraryCall)); templ("encodeArgs", abi.tupleEncoder(argumentTypes, funType.parameterTypes(), encodeForLibraryCall));
templ("argumentString", argumentString); templ("argumentString", joinHumanReadablePrefixed(argumentStrings));
// Output data will replace input data, unless we have ECRecover (then, output // Output data will replace input data, unless we have ECRecover (then, output
// area will be 32 bytes just before input area). // area will be 32 bytes just before input area).

View File

@ -69,10 +69,11 @@ public:
/// The returned IRVariable is itself typed with the type of the stack slot as defined /// The returned IRVariable is itself typed with the type of the stack slot as defined
/// in ``m_type.stackItems()`` and may again occupy multiple stack slots. /// in ``m_type.stackItems()`` and may again occupy multiple stack slots.
IRVariable part(std::string const& _slot) const; IRVariable part(std::string const& _slot) const;
private:
/// @returns a vector containing the names of the stack slots of the variable. /// @returns a vector containing the names of the stack slots of the variable.
std::vector<std::string> stackSlots() const; std::vector<std::string> stackSlots() const;
private:
/// @returns a name consisting of the base name appended with an underscore and @æ _suffix, /// @returns a name consisting of the base name appended with an underscore and @æ _suffix,
/// unless @a _suffix is empty, in which case the base name itself is returned. /// unless @a _suffix is empty, in which case the base name itself is returned.
std::string suffixedName(std::string const& _suffix) const; std::string suffixedName(std::string const& _suffix) const;

View File

@ -33,6 +33,8 @@ contract Main {
} }
} }
// ====
// compileViaYul: also
// ---- // ----
// getFlag() -> true // getFlag() -> true
// getName() -> "abc" // getName() -> "abc"