From 840ff40263e6463962afbbdec12a6b1a20f81a18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Thu, 11 Jun 2020 00:54:12 +0200 Subject: [PATCH 1/3] Define wasm::Type enum and use it for import parameters and result --- libyul/backends/wasm/BinaryTransform.cpp | 17 +++++++++-------- libyul/backends/wasm/BinaryTransform.h | 4 ++-- libyul/backends/wasm/TextTransform.cpp | 16 ++++++++++++++-- libyul/backends/wasm/TextTransform.h | 2 ++ libyul/backends/wasm/WasmAST.h | 10 ++++++++-- libyul/backends/wasm/WasmCodeTransform.cpp | 22 ++++++++++++++++------ libyul/backends/wasm/WasmCodeTransform.h | 2 ++ 7 files changed, 53 insertions(+), 20 deletions(-) diff --git a/libyul/backends/wasm/BinaryTransform.cpp b/libyul/backends/wasm/BinaryTransform.cpp index ce97225e0..4bc43f121 100644 --- a/libyul/backends/wasm/BinaryTransform.cpp +++ b/libyul/backends/wasm/BinaryTransform.cpp @@ -25,6 +25,7 @@ #include #include +#include using namespace std; using namespace solidity; @@ -475,7 +476,7 @@ BinaryTransform::Type BinaryTransform::typeOf(FunctionImport const& _import) { return { encodeTypes(_import.paramTypes), - encodeTypes(_import.returnType ? vector(1, *_import.returnType) : vector()) + encodeTypes(_import.returnType ? vector(1, *_import.returnType) : vector()) }; } @@ -483,26 +484,26 @@ BinaryTransform::Type BinaryTransform::typeOf(FunctionDefinition const& _funDef) { return { - encodeTypes(vector(_funDef.parameterNames.size(), "i64")), - encodeTypes(vector(_funDef.returns ? 1 : 0, "i64")) + encodeTypes(vector(_funDef.parameterNames.size(), wasm::Type::i64)), + encodeTypes(vector(_funDef.returns ? 1 : 0, wasm::Type::i64)) }; } -uint8_t BinaryTransform::encodeType(string const& _typeName) +uint8_t BinaryTransform::encodeType(wasm::Type _type) { - if (_typeName == "i32") + if (_type == wasm::Type::i32) return uint8_t(ValueType::I32); - else if (_typeName == "i64") + else if (_type == wasm::Type::i64) return uint8_t(ValueType::I64); else yulAssert(false, ""); return 0; } -vector BinaryTransform::encodeTypes(vector const& _typeNames) +vector BinaryTransform::encodeTypes(vector const& _types) { vector result; - for (auto const& t: _typeNames) + for (wasm::Type t: _types) result.emplace_back(encodeType(t)); return result; } diff --git a/libyul/backends/wasm/BinaryTransform.h b/libyul/backends/wasm/BinaryTransform.h index f4444b2fd..1f4ecf663 100644 --- a/libyul/backends/wasm/BinaryTransform.h +++ b/libyul/backends/wasm/BinaryTransform.h @@ -71,8 +71,8 @@ private: static Type typeOf(wasm::FunctionImport const& _import); static Type typeOf(wasm::FunctionDefinition const& _funDef); - static uint8_t encodeType(std::string const& _typeName); - static std::vector encodeTypes(std::vector const& _typeNames); + static uint8_t encodeType(wasm::Type _type); + static std::vector encodeTypes(std::vector const& _types); static std::map> typeToFunctionMap( std::vector const& _imports, diff --git a/libyul/backends/wasm/TextTransform.cpp b/libyul/backends/wasm/TextTransform.cpp index fd8eaf746..a14c8069b 100644 --- a/libyul/backends/wasm/TextTransform.cpp +++ b/libyul/backends/wasm/TextTransform.cpp @@ -20,6 +20,8 @@ #include +#include + #include #include @@ -44,9 +46,9 @@ string TextTransform::run(wasm::Module const& _module) { ret += " (import \"" + imp.module + "\" \"" + imp.externalName + "\" (func $" + imp.internalName; if (!imp.paramTypes.empty()) - ret += " (param" + joinHumanReadablePrefixed(imp.paramTypes, " ", " ") + ")"; + ret += " (param" + joinHumanReadablePrefixed(imp.paramTypes | boost::adaptors::transformed(encodeType), " ", " ") + ")"; if (imp.returnType) - ret += " (result " + *imp.returnType + ")"; + ret += " (result " + encodeType(*imp.returnType) + ")"; ret += "))\n"; } @@ -193,3 +195,13 @@ string TextTransform::joinTransformed(vector const& _expressio } return ret; } + +string TextTransform::encodeType(wasm::Type _type) +{ + if (_type == wasm::Type::i32) + return "i32"; + else if (_type == wasm::Type::i64) + return "i64"; + else + yulAssert(false, "Invalid wasm type"); +} diff --git a/libyul/backends/wasm/TextTransform.h b/libyul/backends/wasm/TextTransform.h index ebbca4e9e..b8b21f7f2 100644 --- a/libyul/backends/wasm/TextTransform.h +++ b/libyul/backends/wasm/TextTransform.h @@ -63,6 +63,8 @@ private: std::vector const& _expressions, char _separator = ' ' ); + + static std::string encodeType(wasm::Type _type); }; } diff --git a/libyul/backends/wasm/WasmAST.h b/libyul/backends/wasm/WasmAST.h index 7ba7066cb..e3a3368ea 100644 --- a/libyul/backends/wasm/WasmAST.h +++ b/libyul/backends/wasm/WasmAST.h @@ -30,6 +30,12 @@ namespace solidity::yul::wasm { +enum class Type +{ + i32, + i64, +}; + struct Literal; struct StringLiteral; struct LocalVariable; @@ -76,8 +82,8 @@ struct FunctionImport { std::string module; std::string externalName; std::string internalName; - std::vector paramTypes; - std::optional returnType; + std::vector paramTypes; + std::optional returnType; }; struct FunctionDefinition diff --git a/libyul/backends/wasm/WasmCodeTransform.cpp b/libyul/backends/wasm/WasmCodeTransform.cpp index f23f51eee..0e3a17f00 100644 --- a/libyul/backends/wasm/WasmCodeTransform.cpp +++ b/libyul/backends/wasm/WasmCodeTransform.cpp @@ -127,10 +127,10 @@ wasm::Expression WasmCodeTransform::operator()(FunctionCall const& _call) builtin->name.str().substr(4), builtin->name.str(), {}, - builtin->returns.empty() ? nullopt : make_optional(builtin->returns.front().str()) + builtin->returns.empty() ? nullopt : make_optional(translatedType(builtin->returns.front())) }; for (auto const& param: builtin->parameters) - imp.paramTypes.emplace_back(param.str()); + imp.paramTypes.emplace_back(translatedType(param)); m_functionsToImport[builtin->name] = std::move(imp); } typeConversionNeeded = true; @@ -361,14 +361,14 @@ wasm::Expression WasmCodeTransform::injectTypeConversionIfNeeded(wasm::FunctionC { wasm::FunctionImport const& import = m_functionsToImport.at(YulString{_call.functionName}); for (size_t i = 0; i < _call.arguments.size(); ++i) - if (import.paramTypes.at(i) == "i32") + if (import.paramTypes.at(i) == wasm::Type::i32) _call.arguments[i] = wasm::BuiltinCall{"i32.wrap_i64", make_vector(std::move(_call.arguments[i]))}; else - yulAssert(import.paramTypes.at(i) == "i64", "Unknown type " + import.paramTypes.at(i)); + yulAssert(import.paramTypes.at(i) == wasm::Type::i64, "Invalid Wasm type"); - if (import.returnType && *import.returnType != "i64") + if (import.returnType && *import.returnType != wasm::Type::i64) { - yulAssert(*import.returnType == "i32", "Invalid type " + *import.returnType); + yulAssert(*import.returnType == wasm::Type::i32, "Invalid Wasm type"); return wasm::BuiltinCall{"i64.extend_i32_u", make_vector(std::move(_call))}; } return {std::move(_call)}; @@ -403,3 +403,13 @@ void WasmCodeTransform::allocateGlobals(size_t _amount) m_nameDispenser.newName("global_"_yulstring).str() }); } + +wasm::Type WasmCodeTransform::translatedType(yul::Type _yulType) +{ + if (_yulType == "i32"_yulstring) + return wasm::Type::i32; + else if (_yulType == "i64"_yulstring) + return wasm::Type::i64; + else + yulAssert(false, "This Yul type does not have a corresponding type in Wasm."); +} diff --git a/libyul/backends/wasm/WasmCodeTransform.h b/libyul/backends/wasm/WasmCodeTransform.h index 26000e385..5680269f4 100644 --- a/libyul/backends/wasm/WasmCodeTransform.h +++ b/libyul/backends/wasm/WasmCodeTransform.h @@ -89,6 +89,8 @@ private: /// Makes sure that there are at least @a _amount global variables. void allocateGlobals(size_t _amount); + static wasm::Type translatedType(yul::Type _yulType); + Dialect const& m_dialect; NameDispenser m_nameDispenser; From 6a82d32ef6f494edd9682f2a4495f066ac64d9af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Thu, 28 May 2020 21:20:19 +0200 Subject: [PATCH 2/3] Add the ability to store variable types in wasm AST --- libyul/backends/wasm/BinaryTransform.cpp | 11 ++++++----- libyul/backends/wasm/TextTransform.cpp | 9 +++++---- libyul/backends/wasm/WasmAST.h | 13 ++++++++----- libyul/backends/wasm/WasmCodeTransform.cpp | 18 ++++++++++-------- 4 files changed, 29 insertions(+), 22 deletions(-) diff --git a/libyul/backends/wasm/BinaryTransform.cpp b/libyul/backends/wasm/BinaryTransform.cpp index 4bc43f121..875d93dbf 100644 --- a/libyul/backends/wasm/BinaryTransform.cpp +++ b/libyul/backends/wasm/BinaryTransform.cpp @@ -298,7 +298,8 @@ bytes BinaryTransform::run(Module const& _module) bytes BinaryTransform::operator()(Literal const& _literal) { - return toBytes(Opcode::I64Const) + lebEncodeSigned(_literal.value); + yulAssert(holds_alternative(_literal.value), ""); + return toBytes(Opcode::I64Const) + lebEncodeSigned(get(_literal.value)); } bytes BinaryTransform::operator()(StringLiteral const&) @@ -457,8 +458,8 @@ bytes BinaryTransform::operator()(FunctionDefinition const& _function) m_locals.clear(); size_t varIdx = 0; - for (size_t i = 0; i < _function.parameterNames.size(); ++i) - m_locals[_function.parameterNames[i]] = varIdx++; + for (size_t i = 0; i < _function.parameters.size(); ++i) + m_locals[_function.parameters[i].name] = varIdx++; for (size_t i = 0; i < _function.locals.size(); ++i) m_locals[_function.locals[i].variableName] = varIdx++; @@ -484,8 +485,8 @@ BinaryTransform::Type BinaryTransform::typeOf(FunctionDefinition const& _funDef) { return { - encodeTypes(vector(_funDef.parameterNames.size(), wasm::Type::i64)), - encodeTypes(vector(_funDef.returns ? 1 : 0, wasm::Type::i64)) + encodeTypes(vector(_funDef.parameters.size(), wasm::Type::i64)), + encodeTypes(vector(_funDef.returnType.has_value() ? 1 : 0, wasm::Type::i64)) }; } diff --git a/libyul/backends/wasm/TextTransform.cpp b/libyul/backends/wasm/TextTransform.cpp index a14c8069b..84f2ce972 100644 --- a/libyul/backends/wasm/TextTransform.cpp +++ b/libyul/backends/wasm/TextTransform.cpp @@ -67,7 +67,8 @@ string TextTransform::run(wasm::Module const& _module) string TextTransform::operator()(wasm::Literal const& _literal) { - return "(i64.const " + to_string(_literal.value) + ")"; + yulAssert(holds_alternative(_literal.value), ""); + return "(i64.const " + to_string(get(_literal.value)) + ")"; } string TextTransform::operator()(wasm::StringLiteral const& _literal) @@ -164,9 +165,9 @@ string TextTransform::indented(string const& _in) string TextTransform::transform(wasm::FunctionDefinition const& _function) { string ret = "(func $" + _function.name + "\n"; - for (auto const& param: _function.parameterNames) - ret += " (param $" + param + " i64)\n"; - if (_function.returns) + for (auto const& param: _function.parameters) + ret += " (param $" + param.name + " i64)\n"; + if (_function.returnType.has_value()) ret += " (result i64)\n"; for (auto const& local: _function.locals) ret += " (local $" + local.variableName + " i64)\n"; diff --git a/libyul/backends/wasm/WasmAST.h b/libyul/backends/wasm/WasmAST.h index e3a3368ea..b22b0db84 100644 --- a/libyul/backends/wasm/WasmAST.h +++ b/libyul/backends/wasm/WasmAST.h @@ -36,6 +36,9 @@ enum class Type i64, }; +struct TypedName { std::string name; Type type; }; +using TypedNameList = std::vector; + struct Literal; struct StringLiteral; struct LocalVariable; @@ -56,7 +59,7 @@ using Expression = std::variant< Block, If, Loop, Branch, BranchIf, Return >; -struct Literal { uint64_t value; }; +struct Literal { std::variant value; }; struct StringLiteral { std::string value; }; struct LocalVariable { std::string name; }; struct GlobalVariable { std::string name; }; @@ -76,8 +79,8 @@ struct Branch { Label label; }; struct Return {}; struct BranchIf { Label label; std::unique_ptr condition; }; -struct VariableDeclaration { std::string variableName; }; -struct GlobalVariableDeclaration { std::string variableName; }; +struct VariableDeclaration { std::string variableName; Type type; }; +struct GlobalVariableDeclaration { std::string variableName; Type type; }; struct FunctionImport { std::string module; std::string externalName; @@ -89,8 +92,8 @@ struct FunctionImport { struct FunctionDefinition { std::string name; - std::vector parameterNames; - bool returns; + std::vector parameters; + std::optional returnType; std::vector locals; std::vector body; }; diff --git a/libyul/backends/wasm/WasmCodeTransform.cpp b/libyul/backends/wasm/WasmCodeTransform.cpp index 0e3a17f00..8f987824c 100644 --- a/libyul/backends/wasm/WasmCodeTransform.cpp +++ b/libyul/backends/wasm/WasmCodeTransform.cpp @@ -88,7 +88,7 @@ wasm::Expression WasmCodeTransform::operator()(VariableDeclaration const& _varDe for (auto const& var: _varDecl.variables) { variableNames.emplace_back(var.name.str()); - m_localVariables.emplace_back(wasm::VariableDeclaration{variableNames.back()}); + m_localVariables.emplace_back(wasm::VariableDeclaration{variableNames.back(), wasm::Type::i64}); } if (_varDecl.value) @@ -184,7 +184,7 @@ wasm::Expression WasmCodeTransform::operator()(Literal const& _literal) { u256 value = valueOfLiteral(_literal); yulAssert(value <= numeric_limits::max(), "Literal too large: " + value.str()); - return wasm::Literal{uint64_t(value)}; + return wasm::Literal{static_cast(value)}; } wasm::Expression WasmCodeTransform::operator()(If const& _if) @@ -193,7 +193,7 @@ wasm::Expression WasmCodeTransform::operator()(If const& _if) vector args; args.emplace_back(visitReturnByValue(*_if.condition)); - args.emplace_back(wasm::Literal{0}); + args.emplace_back(wasm::Literal{static_cast(0)}); return wasm::If{ make_unique(wasm::BuiltinCall{"i64.ne", std::move(args)}), visit(_if.body.statements), @@ -205,7 +205,7 @@ wasm::Expression WasmCodeTransform::operator()(Switch const& _switch) { wasm::Block block; string condition = m_nameDispenser.newName("condition"_yulstring).str(); - m_localVariables.emplace_back(wasm::VariableDeclaration{condition}); + m_localVariables.emplace_back(wasm::VariableDeclaration{condition, wasm::Type::i64}); block.statements.emplace_back(wasm::LocalAssignment{condition, visit(*_switch.expression)}); vector* currentBlock = &block.statements; @@ -325,10 +325,11 @@ wasm::FunctionDefinition WasmCodeTransform::translateFunction(yul::FunctionDefin wasm::FunctionDefinition fun; fun.name = _fun.name.str(); for (auto const& param: _fun.parameters) - fun.parameterNames.emplace_back(param.name.str()); + fun.parameters.push_back({param.name.str(), wasm::Type::i64}); for (auto const& retParam: _fun.returnVariables) - fun.locals.emplace_back(wasm::VariableDeclaration{retParam.name.str()}); - fun.returns = !_fun.returnVariables.empty(); + fun.locals.emplace_back(wasm::VariableDeclaration{retParam.name.str(), wasm::Type::i64}); + if (!_fun.returnVariables.empty()) + fun.returnType = wasm::Type::i64; yulAssert(m_localVariables.empty(), ""); yulAssert(m_functionBodyLabel.empty(), ""); @@ -400,7 +401,8 @@ void WasmCodeTransform::allocateGlobals(size_t _amount) { while (m_globalVariables.size() < _amount) m_globalVariables.emplace_back(wasm::GlobalVariableDeclaration{ - m_nameDispenser.newName("global_"_yulstring).str() + m_nameDispenser.newName("global_"_yulstring).str(), + wasm::Type::i64 }); } From e67f5072df6440cef895bf7dcd2c49267895658a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Thu, 28 May 2020 21:40:44 +0200 Subject: [PATCH 3/3] Add support for generating code with i32 variables in text and binary wasm --- libyul/backends/wasm/BinaryTransform.cpp | 98 ++++++++++++++----- libyul/backends/wasm/BinaryTransform.h | 1 + libyul/backends/wasm/TextTransform.cpp | 15 +-- .../args | 1 + .../err | 1 + .../input.yul | 17 ++++ .../output | 73 ++++++++++++++ 7 files changed, 177 insertions(+), 29 deletions(-) create mode 100644 test/cmdlineTests/wasm_to_wasm_function_returning_multiple_values/args create mode 100644 test/cmdlineTests/wasm_to_wasm_function_returning_multiple_values/err create mode 100644 test/cmdlineTests/wasm_to_wasm_function_returning_multiple_values/input.yul create mode 100644 test/cmdlineTests/wasm_to_wasm_function_returning_multiple_values/output diff --git a/libyul/backends/wasm/BinaryTransform.cpp b/libyul/backends/wasm/BinaryTransform.cpp index 875d93dbf..b305b9c55 100644 --- a/libyul/backends/wasm/BinaryTransform.cpp +++ b/libyul/backends/wasm/BinaryTransform.cpp @@ -22,6 +22,7 @@ #include #include +#include #include #include @@ -83,6 +84,16 @@ bytes toBytes(ValueType _vt) return toBytes(uint8_t(_vt)); } +ValueType toValueType(wasm::Type _type) +{ + if (_type == wasm::Type::i32) + return ValueType::I32; + else if (_type == wasm::Type::i64) + return ValueType::I64; + else + yulAssert(false, "Invalid wasm variable type"); +} + enum class Export: uint8_t { Function = 0x0, @@ -132,6 +143,16 @@ bytes toBytes(Opcode _o) return toBytes(uint8_t(_o)); } +Opcode constOpcodeFor(ValueType _type) +{ + if (_type == ValueType::I32) + return Opcode::I32Const; + else if (_type == ValueType::I64) + return Opcode::I64Const; + else + yulAssert(false, "Values of this type cannot be used with const opcode"); +} + static map const builtins = { {"i32.load", 0x28}, {"i64.load", 0x29}, @@ -250,6 +271,34 @@ bytes makeSection(Section _section, bytes _data) return toBytes(_section) + prefixSize(move(_data)); } +/// This is a kind of run-length-encoding of local types. +vector> groupLocalVariables(vector _localVariables) +{ + vector> localEntries; + + size_t entrySize = 0; + ValueType entryType = ValueType::I32; // Any type would work here + for (VariableDeclaration const& localVariable: _localVariables) + { + ValueType variableType = toValueType(localVariable.type); + + if (variableType != entryType) + { + if (entrySize > 0) + localEntries.emplace_back(entrySize, entryType); + + entryType = variableType; + entrySize = 0; + } + + ++entrySize; + } + if (entrySize > 0) + localEntries.emplace_back(entrySize, entryType); + + return localEntries; +} + } bytes BinaryTransform::run(Module const& _module) @@ -298,8 +347,10 @@ bytes BinaryTransform::run(Module const& _module) bytes BinaryTransform::operator()(Literal const& _literal) { - yulAssert(holds_alternative(_literal.value), ""); - return toBytes(Opcode::I64Const) + lebEncodeSigned(get(_literal.value)); + return std::visit(GenericVisitor{ + [&](uint32_t _value) -> bytes { return toBytes(Opcode::I32Const) + lebEncodeSigned(static_cast(_value)); }, + [&](uint64_t _value) -> bytes { return toBytes(Opcode::I64Const) + lebEncodeSigned(static_cast(_value)); }, + }, _literal.value); } bytes BinaryTransform::operator()(StringLiteral const&) @@ -445,15 +496,12 @@ bytes BinaryTransform::operator()(FunctionDefinition const& _function) { bytes ret; - // This is a kind of run-length-encoding of local types. Has to be adapted once - // we have locals of different types. - if (_function.locals.size() == 0) - ret += lebEncode(0); // number of locals groups - else + vector> localEntries = groupLocalVariables(_function.locals); + ret += lebEncode(localEntries.size()); + for (pair const& entry: localEntries) { - ret += lebEncode(1); // number of locals groups - ret += lebEncode(_function.locals.size()); - ret += toBytes(ValueType::I64); + ret += lebEncode(entry.first); + ret += toBytes(entry.second); } m_locals.clear(); @@ -483,22 +531,15 @@ BinaryTransform::Type BinaryTransform::typeOf(FunctionImport const& _import) BinaryTransform::Type BinaryTransform::typeOf(FunctionDefinition const& _funDef) { - return { - encodeTypes(vector(_funDef.parameters.size(), wasm::Type::i64)), - encodeTypes(vector(_funDef.returnType.has_value() ? 1 : 0, wasm::Type::i64)) + encodeTypes(_funDef.parameters), + encodeTypes(_funDef.returnType ? vector(1, *_funDef.returnType) : vector()) }; } uint8_t BinaryTransform::encodeType(wasm::Type _type) { - if (_type == wasm::Type::i32) - return uint8_t(ValueType::I32); - else if (_type == wasm::Type::i64) - return uint8_t(ValueType::I64); - else - yulAssert(false, ""); - return 0; + return uint8_t(toValueType(_type)); } vector BinaryTransform::encodeTypes(vector const& _types) @@ -509,6 +550,14 @@ vector BinaryTransform::encodeTypes(vector const& _types) return result; } +vector BinaryTransform::encodeTypes(wasm::TypedNameList const& _typedNameList) +{ + vector result; + for (TypedName const& typedName: _typedNameList) + result.emplace_back(encodeType(typedName.type)); + return result; +} + map> BinaryTransform::typeToFunctionMap( vector const& _imports, vector const& _functions @@ -614,13 +663,16 @@ bytes BinaryTransform::memorySection() bytes BinaryTransform::globalSection(vector const& _globals) { bytes result = lebEncode(_globals.size()); - for (size_t i = 0; i < _globals.size(); ++i) + for (wasm::GlobalVariableDeclaration const& global: _globals) + { + ValueType globalType = toValueType(global.type); result += - toBytes(ValueType::I64) + + toBytes(globalType) + lebEncode(static_cast(Mutability::Var)) + - toBytes(Opcode::I64Const) + + toBytes(constOpcodeFor(globalType)) + lebEncodeSigned(0) + toBytes(Opcode::End); + } return makeSection(Section::GLOBAL, move(result)); } diff --git a/libyul/backends/wasm/BinaryTransform.h b/libyul/backends/wasm/BinaryTransform.h index 1f4ecf663..c505fe2dc 100644 --- a/libyul/backends/wasm/BinaryTransform.h +++ b/libyul/backends/wasm/BinaryTransform.h @@ -73,6 +73,7 @@ private: static uint8_t encodeType(wasm::Type _type); static std::vector encodeTypes(std::vector const& _types); + static std::vector encodeTypes(wasm::TypedNameList const& _typedNameList); static std::map> typeToFunctionMap( std::vector const& _imports, diff --git a/libyul/backends/wasm/TextTransform.cpp b/libyul/backends/wasm/TextTransform.cpp index 84f2ce972..b7f1e81ea 100644 --- a/libyul/backends/wasm/TextTransform.cpp +++ b/libyul/backends/wasm/TextTransform.cpp @@ -23,6 +23,7 @@ #include #include +#include #include #include @@ -58,7 +59,7 @@ string TextTransform::run(wasm::Module const& _module) ret += " (export \"main\" (func $main))\n"; for (auto const& g: _module.globals) - ret += " (global $" + g.variableName + " (mut i64) (i64.const 0))\n"; + ret += " (global $" + g.variableName + " (mut " + encodeType(g.type) + ") (" + encodeType(g.type) + ".const 0))\n"; ret += "\n"; for (auto const& f: _module.functions) ret += transform(f) + "\n"; @@ -67,8 +68,10 @@ string TextTransform::run(wasm::Module const& _module) string TextTransform::operator()(wasm::Literal const& _literal) { - yulAssert(holds_alternative(_literal.value), ""); - return "(i64.const " + to_string(get(_literal.value)) + ")"; + return std::visit(GenericVisitor{ + [&](uint32_t _value) -> string { return "(i32.const " + to_string(_value) + ")"; }, + [&](uint64_t _value) -> string { return "(i64.const " + to_string(_value) + ")"; }, + }, _literal.value); } string TextTransform::operator()(wasm::StringLiteral const& _literal) @@ -166,11 +169,11 @@ string TextTransform::transform(wasm::FunctionDefinition const& _function) { string ret = "(func $" + _function.name + "\n"; for (auto const& param: _function.parameters) - ret += " (param $" + param.name + " i64)\n"; + ret += " (param $" + param.name + " " + encodeType(param.type) + ")\n"; if (_function.returnType.has_value()) - ret += " (result i64)\n"; + ret += " (result " + encodeType(_function.returnType.value()) + ")\n"; for (auto const& local: _function.locals) - ret += " (local $" + local.variableName + " i64)\n"; + ret += " (local $" + local.variableName + " " + encodeType(local.type) + ")\n"; ret += indented(joinTransformed(_function.body, '\n')); if (ret.back() != '\n') ret += '\n'; diff --git a/test/cmdlineTests/wasm_to_wasm_function_returning_multiple_values/args b/test/cmdlineTests/wasm_to_wasm_function_returning_multiple_values/args new file mode 100644 index 000000000..04cd5f05b --- /dev/null +++ b/test/cmdlineTests/wasm_to_wasm_function_returning_multiple_values/args @@ -0,0 +1 @@ +--yul --yul-dialect ewasm --machine ewasm diff --git a/test/cmdlineTests/wasm_to_wasm_function_returning_multiple_values/err b/test/cmdlineTests/wasm_to_wasm_function_returning_multiple_values/err new file mode 100644 index 000000000..014a1178f --- /dev/null +++ b/test/cmdlineTests/wasm_to_wasm_function_returning_multiple_values/err @@ -0,0 +1 @@ +Warning: Yul is still experimental. Please use the output with care. diff --git a/test/cmdlineTests/wasm_to_wasm_function_returning_multiple_values/input.yul b/test/cmdlineTests/wasm_to_wasm_function_returning_multiple_values/input.yul new file mode 100644 index 000000000..2b1a6d960 --- /dev/null +++ b/test/cmdlineTests/wasm_to_wasm_function_returning_multiple_values/input.yul @@ -0,0 +1,17 @@ +object "object" { + code { + function main() + { + let m:i64, n:i32, p:i32, q:i64 := multireturn(1:i32, 2:i64, 3:i64, 4:i32) + } + + function multireturn(a:i32, b:i64, c:i64, d:i32) -> x:i64, y:i32, z:i32, w:i64 + { + x := b + w := c + + y := a + z := d + } + } +} diff --git a/test/cmdlineTests/wasm_to_wasm_function_returning_multiple_values/output b/test/cmdlineTests/wasm_to_wasm_function_returning_multiple_values/output new file mode 100644 index 000000000..a99808601 --- /dev/null +++ b/test/cmdlineTests/wasm_to_wasm_function_returning_multiple_values/output @@ -0,0 +1,73 @@ + +======= wasm_to_wasm_function_returning_multiple_values/input.yul (Ewasm) ======= + +Pretty printed source: +object "object" { + code { + function main() + { + let m, n:i32, p:i32, q := multireturn(1:i32, 2, 3, 4:i32) + } + function multireturn(a:i32, b, c, d:i32) -> x, y:i32, z:i32, w + { + x := b + w := c + y := a + z := d + } + } +} + + +Binary representation: +0061736d01000000010c0260000060047e7e7e7e017e020100030302000105030100010610037e0142000b7e0142000b7e0142000b071102066d656d6f72790200046d61696e00000a4a022201047e024002404201420242034204100121002300210123012102230221030b0b0b2501047e0240200121042002210720002105200321060b20052400200624012007240220040b + +Text representation: +(module + (memory $memory (export "memory") 1) + (export "main" (func $main)) + (global $global_ (mut i64) (i64.const 0)) + (global $global__1 (mut i64) (i64.const 0)) + (global $global__2 (mut i64) (i64.const 0)) + +(func $main + (local $m i64) + (local $n i64) + (local $p i64) + (local $q i64) + (block $label_ + (block + (local.set $m (call $multireturn (i64.const 1) (i64.const 2) (i64.const 3) (i64.const 4))) + (local.set $n (global.get $global_)) + (local.set $p (global.get $global__1)) + (local.set $q (global.get $global__2)) + + ) + + ) +) + +(func $multireturn + (param $a i64) + (param $b i64) + (param $c i64) + (param $d i64) + (result i64) + (local $x i64) + (local $y i64) + (local $z i64) + (local $w i64) + (block $label__3 + (local.set $x (local.get $b)) + (local.set $w (local.get $c)) + (local.set $y (local.get $a)) + (local.set $z (local.get $d)) + + ) + (global.set $global_ (local.get $y)) + (global.set $global__1 (local.get $z)) + (global.set $global__2 (local.get $w)) + (local.get $x) +) + +)