Add LiteralKind to Dialect.literalArguments

Co-authored-by: Daniel Kirchner <daniel@ekpyron.org>
This commit is contained in:
Alex Beregszaszi 2020-08-04 16:30:16 +01:00
parent b8fd409f7f
commit f6a57af809
10 changed files with 51 additions and 55 deletions

View File

@ -272,14 +272,14 @@ vector<YulString> AsmAnalyzer::operator()(FunctionCall const& _funCall)
auto watcher = m_errorReporter.errorWatcher(); auto watcher = m_errorReporter.errorWatcher();
vector<YulString> const* parameterTypes = nullptr; vector<YulString> const* parameterTypes = nullptr;
vector<YulString> const* returnTypes = nullptr; vector<YulString> const* returnTypes = nullptr;
vector<bool> const* needsLiteralArguments = nullptr; vector<optional<LiteralKind>> const* literalArguments = nullptr;
if (BuiltinFunction const* f = m_dialect.builtin(_funCall.functionName.name)) if (BuiltinFunction const* f = m_dialect.builtin(_funCall.functionName.name))
{ {
parameterTypes = &f->parameters; parameterTypes = &f->parameters;
returnTypes = &f->returns; returnTypes = &f->returns;
if (f->literalArguments) if (!f->literalArguments.empty())
needsLiteralArguments = &f->literalArguments.value(); literalArguments = &f->literalArguments;
validateInstructions(_funCall); validateInstructions(_funCall);
} }
@ -318,7 +318,7 @@ vector<YulString> AsmAnalyzer::operator()(FunctionCall const& _funCall)
for (size_t i = _funCall.arguments.size(); i > 0; i--) for (size_t i = _funCall.arguments.size(); i > 0; i--)
{ {
Expression const& arg = _funCall.arguments[i - 1]; Expression const& arg = _funCall.arguments[i - 1];
bool isLiteralArgument = needsLiteralArguments && (*needsLiteralArguments)[i - 1]; bool isLiteralArgument = literalArguments && (*literalArguments)[i - 1].has_value();
bool isStringLiteral = holds_alternative<Literal>(arg) && get<Literal>(arg).kind == LiteralKind::String; bool isStringLiteral = holds_alternative<Literal>(arg) && get<Literal>(arg).kind == LiteralKind::String;
if (isLiteralArgument && isStringLiteral) if (isLiteralArgument && isStringLiteral)

View File

@ -48,8 +48,13 @@ struct BuiltinFunction
ControlFlowSideEffects controlFlowSideEffects; ControlFlowSideEffects controlFlowSideEffects;
/// If true, this is the msize instruction. /// If true, this is the msize instruction.
bool isMSize = false; bool isMSize = false;
/// If set, same length as the arguments, if true at index i, the i'th argument has to be a literal which means it can't be moved to variables. /// Must be empty or the same length as the arguments.
std::optional<std::vector<bool>> literalArguments; /// If set at index i, the i'th argument has to be a literal which means it can't be moved to variables.
std::vector<std::optional<LiteralKind>> literalArguments{};
std::optional<LiteralKind> literalArgument(size_t i) const
{
return literalArguments.empty() ? std::nullopt : literalArguments.at(i);
}
}; };
struct Dialect: boost::noncopyable struct Dialect: boost::noncopyable

View File

@ -70,7 +70,7 @@ pair<YulString, BuiltinFunctionForEVM> createEVMFunction(
f.controlFlowSideEffects.terminates = evmasm::SemanticInformation::terminatesControlFlow(_instruction); f.controlFlowSideEffects.terminates = evmasm::SemanticInformation::terminatesControlFlow(_instruction);
f.controlFlowSideEffects.reverts = evmasm::SemanticInformation::reverts(_instruction); f.controlFlowSideEffects.reverts = evmasm::SemanticInformation::reverts(_instruction);
f.isMSize = _instruction == evmasm::Instruction::MSIZE; f.isMSize = _instruction == evmasm::Instruction::MSIZE;
f.literalArguments.reset(); f.literalArguments.clear();
f.instruction = _instruction; f.instruction = _instruction;
f.generateCode = [_instruction]( f.generateCode = [_instruction](
FunctionCall const& _call, FunctionCall const& _call,
@ -90,7 +90,7 @@ pair<YulString, BuiltinFunctionForEVM> createFunction(
size_t _params, size_t _params,
size_t _returns, size_t _returns,
SideEffects _sideEffects, SideEffects _sideEffects,
vector<bool> _literalArguments, vector<optional<LiteralKind>> _literalArguments,
std::function<void(FunctionCall const&, AbstractAssembly&, BuiltinContext&, std::function<void(Expression const&)>)> _generateCode std::function<void(FunctionCall const&, AbstractAssembly&, BuiltinContext&, std::function<void(Expression const&)>)> _generateCode
) )
{ {
@ -102,10 +102,7 @@ pair<YulString, BuiltinFunctionForEVM> createFunction(
f.parameters.resize(_params); f.parameters.resize(_params);
f.returns.resize(_returns); f.returns.resize(_returns);
f.sideEffects = std::move(_sideEffects); f.sideEffects = std::move(_sideEffects);
if (!_literalArguments.empty())
f.literalArguments = std::move(_literalArguments); f.literalArguments = std::move(_literalArguments);
else
f.literalArguments.reset();
f.isMSize = false; f.isMSize = false;
f.instruction = {}; f.instruction = {};
f.generateCode = std::move(_generateCode); f.generateCode = std::move(_generateCode);
@ -135,7 +132,7 @@ map<YulString, BuiltinFunctionForEVM> createBuiltins(langutil::EVMVersion _evmVe
if (_objectAccess) if (_objectAccess)
{ {
builtins.emplace(createFunction("linkersymbol", 1, 1, SideEffects{}, {true}, []( builtins.emplace(createFunction("linkersymbol", 1, 1, SideEffects{}, {LiteralKind::String}, [](
FunctionCall const& _call, FunctionCall const& _call,
AbstractAssembly& _assembly, AbstractAssembly& _assembly,
BuiltinContext&, BuiltinContext&,
@ -145,7 +142,7 @@ map<YulString, BuiltinFunctionForEVM> createBuiltins(langutil::EVMVersion _evmVe
Expression const& arg = _call.arguments.front(); Expression const& arg = _call.arguments.front();
_assembly.appendLinkerSymbol(std::get<Literal>(arg).value.str()); _assembly.appendLinkerSymbol(std::get<Literal>(arg).value.str());
})); }));
builtins.emplace(createFunction("datasize", 1, 1, SideEffects{}, {true}, []( builtins.emplace(createFunction("datasize", 1, 1, SideEffects{}, {LiteralKind::String}, [](
FunctionCall const& _call, FunctionCall const& _call,
AbstractAssembly& _assembly, AbstractAssembly& _assembly,
BuiltinContext& _context, BuiltinContext& _context,
@ -167,7 +164,7 @@ map<YulString, BuiltinFunctionForEVM> createBuiltins(langutil::EVMVersion _evmVe
_assembly.appendDataSize(subIdPath); _assembly.appendDataSize(subIdPath);
} }
})); }));
builtins.emplace(createFunction("dataoffset", 1, 1, SideEffects{}, {true}, []( builtins.emplace(createFunction("dataoffset", 1, 1, SideEffects{}, {LiteralKind::String}, [](
FunctionCall const& _call, FunctionCall const& _call,
AbstractAssembly& _assembly, AbstractAssembly& _assembly,
BuiltinContext& _context, BuiltinContext& _context,
@ -210,7 +207,7 @@ map<YulString, BuiltinFunctionForEVM> createBuiltins(langutil::EVMVersion _evmVe
2, 2,
0, 0,
SideEffects{false, false, false, false, true}, SideEffects{false, false, false, false, true},
{true, false}, {LiteralKind::String, std::nullopt},
[]( [](
FunctionCall const& _call, FunctionCall const& _call,
AbstractAssembly& _assembly, AbstractAssembly& _assembly,
@ -230,7 +227,7 @@ map<YulString, BuiltinFunctionForEVM> createBuiltins(langutil::EVMVersion _evmVe
1, 1,
1, 1,
SideEffects{}, SideEffects{},
{true}, {LiteralKind::String},
[]( [](
FunctionCall const& _call, FunctionCall const& _call,
AbstractAssembly& _assembly, AbstractAssembly& _assembly,

View File

@ -170,7 +170,7 @@ NoOutputEVMDialect::NoOutputEVMDialect(EVMDialect const& _copyFrom):
for (size_t j = 0; j < _call.arguments.size(); j++) for (size_t j = 0; j < _call.arguments.size(); j++)
{ {
size_t const i = _call.arguments.size() - j - 1; size_t const i = _call.arguments.size() - j - 1;
if (!(fun.second.literalArguments && (*fun.second.literalArguments)[i])) if (!fun.second.literalArgument(i))
{ {
_visitExpression(_call.arguments[i]); _visitExpression(_call.arguments[i]);
visited++; visited++;

View File

@ -140,22 +140,20 @@ wasm::Expression WasmCodeTransform::operator()(FunctionCall const& _call)
m_functionsToImport[builtin->name] = std::move(imp); m_functionsToImport[builtin->name] = std::move(imp);
} }
} }
else if (builtin->literalArguments && contains(builtin->literalArguments.value(), true))
{
vector<wasm::Expression> literals;
for (size_t i = 0; i < _call.arguments.size(); i++)
if (builtin->literalArguments.value()[i])
literals.emplace_back(wasm::StringLiteral{std::get<Literal>(_call.arguments[i]).value.str()});
else else
literals.emplace_back(visitReturnByValue(_call.arguments[i])); {
vector<wasm::Expression> arguments;
return wasm::BuiltinCall{_call.functionName.name.str(), std::move(literals)}; for (size_t i = 0; i < _call.arguments.size(); i++)
if (builtin->literalArgument(i))
{
yulAssert(builtin->literalArgument(i) == LiteralKind::String, "");
arguments.emplace_back(wasm::StringLiteral{std::get<Literal>(_call.arguments[i]).value.str()});
} }
else else
return wasm::BuiltinCall{ arguments.emplace_back(visitReturnByValue(_call.arguments[i]));
_call.functionName.name.str(),
visit(_call.arguments) return wasm::BuiltinCall{_call.functionName.name.str(), std::move(arguments)};
}; }
} }
// If this function returns multiple values, then the first one will // If this function returns multiple values, then the first one will

View File

@ -21,6 +21,7 @@
#include <libyul/backends/wasm/WasmDialect.h> #include <libyul/backends/wasm/WasmDialect.h>
#include <libyul/AsmData.h>
#include <libyul/Exceptions.h> #include <libyul/Exceptions.h>
using namespace std; using namespace std;
@ -119,8 +120,8 @@ WasmDialect::WasmDialect()
m_functions["unreachable"_yulstring].controlFlowSideEffects.terminates = true; m_functions["unreachable"_yulstring].controlFlowSideEffects.terminates = true;
m_functions["unreachable"_yulstring].controlFlowSideEffects.reverts = true; m_functions["unreachable"_yulstring].controlFlowSideEffects.reverts = true;
addFunction("datasize", {i64}, {i64}, true, {true}); addFunction("datasize", {i64}, {i64}, true, {LiteralKind::String});
addFunction("dataoffset", {i64}, {i64}, true, {true}); addFunction("dataoffset", {i64}, {i64}, true, {LiteralKind::String});
addEthereumExternals(); addEthereumExternals();
} }
@ -221,7 +222,7 @@ void WasmDialect::addEthereumExternals()
f.controlFlowSideEffects = ext.controlFlowSideEffects; f.controlFlowSideEffects = ext.controlFlowSideEffects;
f.isMSize = false; f.isMSize = false;
f.sideEffects.invalidatesStorage = (ext.name == "storageStore"); f.sideEffects.invalidatesStorage = (ext.name == "storageStore");
f.literalArguments.reset(); f.literalArguments.clear();
} }
} }
@ -230,7 +231,7 @@ void WasmDialect::addFunction(
vector<YulString> _params, vector<YulString> _params,
vector<YulString> _returns, vector<YulString> _returns,
bool _movable, bool _movable,
std::vector<bool> _literalArguments vector<optional<LiteralKind>> _literalArguments
) )
{ {
YulString name{move(_name)}; YulString name{move(_name)};
@ -241,8 +242,5 @@ void WasmDialect::addFunction(
f.returns = std::move(_returns); f.returns = std::move(_returns);
f.sideEffects = _movable ? SideEffects{} : SideEffects::worst(); f.sideEffects = _movable ? SideEffects{} : SideEffects::worst();
f.isMSize = false; f.isMSize = false;
if (!_literalArguments.empty())
f.literalArguments = std::move(_literalArguments); f.literalArguments = std::move(_literalArguments);
else
f.literalArguments.reset();
} }

View File

@ -62,7 +62,7 @@ private:
std::vector<YulString> _params, std::vector<YulString> _params,
std::vector<YulString> _returns, std::vector<YulString> _returns,
bool _movable = true, bool _movable = true,
std::vector<bool> _literalArguments = std::vector<bool>{} std::vector<std::optional<LiteralKind>> _literalArguments = std::vector<std::optional<LiteralKind>>{}
); );
std::map<YulString, BuiltinFunction> m_functions; std::map<YulString, BuiltinFunction> m_functions;

View File

@ -42,16 +42,16 @@ void WordSizeTransform::operator()(FunctionDefinition& _fd)
void WordSizeTransform::operator()(FunctionCall& _fc) void WordSizeTransform::operator()(FunctionCall& _fc)
{ {
vector<bool> const* literalArguments = nullptr; vector<optional<LiteralKind>> const* literalArguments = nullptr;
if (BuiltinFunction const* fun = m_inputDialect.builtin(_fc.functionName.name)) if (BuiltinFunction const* fun = m_inputDialect.builtin(_fc.functionName.name))
if (fun->literalArguments) if (!fun->literalArguments.empty())
literalArguments = &fun->literalArguments.value(); literalArguments = &fun->literalArguments;
vector<Expression> newArgs; vector<Expression> newArgs;
for (size_t i = 0; i < _fc.arguments.size(); i++) for (size_t i = 0; i < _fc.arguments.size(); i++)
if (!literalArguments || !(*literalArguments)[i]) if (!literalArguments || !(*literalArguments)[i].has_value())
newArgs += expandValueToVector(_fc.arguments[i]); newArgs += expandValueToVector(_fc.arguments[i]);
else else
{ {
@ -109,7 +109,8 @@ void WordSizeTransform::operator()(Block& _block)
if (BuiltinFunction const* f = m_inputDialect.builtin(std::get<FunctionCall>(*varDecl.value).functionName.name)) if (BuiltinFunction const* f = m_inputDialect.builtin(std::get<FunctionCall>(*varDecl.value).functionName.name))
if (f->name == "datasize"_yulstring || f->name == "dataoffset"_yulstring) if (f->name == "datasize"_yulstring || f->name == "dataoffset"_yulstring)
{ {
yulAssert(f->literalArguments && f->literalArguments.value()[0], ""); yulAssert(f->literalArguments.size() == 1, "");
yulAssert(f->literalArguments.at(0) == LiteralKind::String, "");
yulAssert(varDecl.variables.size() == 1, ""); yulAssert(varDecl.variables.size() == 1, "");
auto newLhs = generateU64IdentifierNames(varDecl.variables[0].name); auto newLhs = generateU64IdentifierNames(varDecl.variables[0].name);
vector<Statement> ret; vector<Statement> ret;
@ -169,7 +170,8 @@ void WordSizeTransform::operator()(Block& _block)
if (BuiltinFunction const* f = m_inputDialect.builtin(std::get<FunctionCall>(*assignment.value).functionName.name)) if (BuiltinFunction const* f = m_inputDialect.builtin(std::get<FunctionCall>(*assignment.value).functionName.name))
if (f->name == "datasize"_yulstring || f->name == "dataoffset"_yulstring) if (f->name == "datasize"_yulstring || f->name == "dataoffset"_yulstring)
{ {
yulAssert(f->literalArguments && f->literalArguments.value()[0], ""); yulAssert(f->literalArguments.size() == 1, "");
yulAssert(f->literalArguments[0] == LiteralKind::String, "");
yulAssert(assignment.variableNames.size() == 1, ""); yulAssert(assignment.variableNames.size() == 1, "");
auto newLhs = generateU64IdentifierNames(assignment.variableNames[0].name); auto newLhs = generateU64IdentifierNames(assignment.variableNames[0].name);
vector<Statement> ret; vector<Statement> ret;

View File

@ -67,7 +67,7 @@ void CommonSubexpressionEliminator::visit(Expression& _e)
// We should not modify function arguments that have to be literals // We should not modify function arguments that have to be literals
// Note that replacing the function call entirely is fine, // Note that replacing the function call entirely is fine,
// if the function call is movable. // if the function call is movable.
if (!builtin->literalArguments || !builtin->literalArguments.value()[i - 1]) if (!builtin->literalArgument(i - 1))
visit(funCall.arguments[i - 1]); visit(funCall.arguments[i - 1]);
descend = false; descend = false;

View File

@ -46,14 +46,10 @@ void ExpressionSplitter::run(OptimiserStepContext& _context, Block& _ast)
void ExpressionSplitter::operator()(FunctionCall& _funCall) void ExpressionSplitter::operator()(FunctionCall& _funCall)
{ {
vector<bool> const* literalArgs = nullptr; BuiltinFunction const* builtin = m_dialect.builtin(_funCall.functionName.name);
if (BuiltinFunction const* builtin = m_dialect.builtin(_funCall.functionName.name))
if (builtin->literalArguments)
literalArgs = &builtin->literalArguments.value();
for (size_t i = _funCall.arguments.size(); i > 0; i--) for (size_t i = _funCall.arguments.size(); i > 0; i--)
if (!literalArgs || !(*literalArgs)[i - 1]) if (!builtin || !builtin->literalArgument(i - 1))
outlineExpression(_funCall.arguments[i - 1]); outlineExpression(_funCall.arguments[i - 1]);
} }