Add i32 functions to wasm dialect.

This commit is contained in:
chriseth 2020-01-30 19:40:06 +01:00
parent 7cca036f4c
commit 8f546849f2
2 changed files with 69 additions and 46 deletions

View File

@ -20,70 +20,86 @@
#include <libyul/backends/wasm/WasmDialect.h> #include <libyul/backends/wasm/WasmDialect.h>
#include <libyul/Exceptions.h>
using namespace std; using namespace std;
using namespace solidity::yul; using namespace solidity::yul;
WasmDialect::WasmDialect() WasmDialect::WasmDialect()
{ {
defaultType = "i64"_yulstring; YulString i64 = "i64"_yulstring;
boolType = "i64"_yulstring; YulString i32 = "i32"_yulstring;
types = {"i64"_yulstring, "i32"_yulstring}; defaultType = i64;
boolType = i32;
types = {i64, i32};
for (auto const& name: { for (auto t: types)
"i64.add", for (auto const& name: {
"i64.sub", "add",
"i64.mul", "sub",
"i64.div_u", "mul",
"i64.rem_u", "div_u",
"i64.and", "rem_u",
"i64.or", "and",
"i64.xor", "or",
"i64.shl", "xor",
"i64.shr_u", "shl",
"i64.eq", "shr_u",
"i64.ne", })
"i64.lt_u", addFunction(t.str() + "." + name, {t, t}, {t});
"i64.gt_u",
"i64.le_u",
"i64.ge_u"
})
addFunction(name, 2, 1);
m_functions["i64.lt_u"_yulstring].returns.front() = "i32"_yulstring; for (auto t: types)
m_functions["i64.gt_u"_yulstring].returns.front() = "i32"_yulstring; for (auto const& name: {
m_functions["i64.le_u"_yulstring].returns.front() = "i32"_yulstring; "eq",
m_functions["i64.ge_u"_yulstring].returns.front() = "i32"_yulstring; "ne",
m_functions["i64.eq"_yulstring].returns.front() = "i32"_yulstring; "lt_u",
m_functions["i64.ne"_yulstring].returns.front() = "i32"_yulstring; "gt_u",
"le_u",
"ge_u"
})
addFunction(t.str() + "." + name, {t, t}, {i32});
addFunction("i64.eqz", 1, 1); addFunction("i32.eqz", {i32}, {i32});
m_functions["i64.eqz"_yulstring].returns.front() = "i32"_yulstring; addFunction("i64.eqz", {i64}, {i32});
addFunction("i64.clz", 1, 1); addFunction("i32.clz", {i32}, {i32});
addFunction("i64.clz", {i64}, {i64});
addFunction("i64.store", 2, 0, false); addFunction("i32.wrap_i64", {i64}, {i32});
m_functions["i64.store"_yulstring].parameters.front() = "i32"_yulstring;
addFunction("i64.extend_i32_u", {i32}, {i64});
addFunction("i32.store", {i32, i32}, {}, false);
m_functions["i32.store"_yulstring].sideEffects.invalidatesStorage = false;
addFunction("i64.store", {i32, i64}, {}, false);
m_functions["i64.store"_yulstring].sideEffects.invalidatesStorage = false; m_functions["i64.store"_yulstring].sideEffects.invalidatesStorage = false;
addFunction("i64.store8", 2, 0, false); addFunction("i32.store8", {i32, i32}, {}, false);
m_functions["i64.store8"_yulstring].parameters.front() = "i32"_yulstring; m_functions["i32.store8"_yulstring].sideEffects.invalidatesStorage = false;
addFunction("i64.store8", {i32, i64}, {}, false);
m_functions["i64.store8"_yulstring].sideEffects.invalidatesStorage = false; m_functions["i64.store8"_yulstring].sideEffects.invalidatesStorage = false;
addFunction("i64.load", 1, 1, false); addFunction("i32.load", {i32}, {i32}, false);
m_functions["i64.load"_yulstring].parameters.front() = "i32"_yulstring; m_functions["i32.load"_yulstring].sideEffects.invalidatesStorage = false;
m_functions["i32.load"_yulstring].sideEffects.invalidatesMemory = false;
m_functions["i32.load"_yulstring].sideEffects.sideEffectFree = true;
m_functions["i32.load"_yulstring].sideEffects.sideEffectFreeIfNoMSize = true;
addFunction("i64.load", {i32}, {i64}, false);
m_functions["i64.load"_yulstring].sideEffects.invalidatesStorage = false; m_functions["i64.load"_yulstring].sideEffects.invalidatesStorage = false;
m_functions["i64.load"_yulstring].sideEffects.invalidatesMemory = false; m_functions["i64.load"_yulstring].sideEffects.invalidatesMemory = false;
m_functions["i64.load"_yulstring].sideEffects.sideEffectFree = true; m_functions["i64.load"_yulstring].sideEffects.sideEffectFree = true;
m_functions["i64.load"_yulstring].sideEffects.sideEffectFreeIfNoMSize = true; m_functions["i64.load"_yulstring].sideEffects.sideEffectFreeIfNoMSize = true;
addFunction("drop", 1, 0); // Drop is actually overloaded for all types, but Yul does not support that.
// We could introduce "i32.drop".
addFunction("drop", {i64}, {});
addFunction("unreachable", 0, 0, false); addFunction("unreachable", {}, {}, false);
m_functions["unreachable"_yulstring].sideEffects.invalidatesStorage = false; m_functions["unreachable"_yulstring].sideEffects.invalidatesStorage = false;
m_functions["unreachable"_yulstring].sideEffects.invalidatesMemory = false; m_functions["unreachable"_yulstring].sideEffects.invalidatesMemory = false;
addFunction("datasize", 1, 1, true, true); addFunction("datasize", {i64}, {i64}, true, true);
addFunction("dataoffset", 1, 1, true, true); addFunction("dataoffset", {i64}, {i64}, true, true);
addEthereumExternals(); addEthereumExternals();
} }
@ -167,8 +183,8 @@ void WasmDialect::addEthereumExternals()
void WasmDialect::addFunction( void WasmDialect::addFunction(
string _name, string _name,
size_t _params, vector<YulString> _params,
size_t _returns, vector<YulString> _returns,
bool _movable, bool _movable,
bool _literalArguments bool _literalArguments
) )
@ -176,8 +192,9 @@ void WasmDialect::addFunction(
YulString name{move(_name)}; YulString name{move(_name)};
BuiltinFunction& f = m_functions[name]; BuiltinFunction& f = m_functions[name];
f.name = name; f.name = name;
f.parameters.resize(_params); f.parameters = std::move(_params);
f.returns.resize(_returns); yulAssert(_returns.size() <= 1, "The Wasm 1.0 specification only allows up to 1 return value.");
f.returns = std::move(_returns);
f.sideEffects = _movable ? SideEffects{} : SideEffects::worst(); f.sideEffects = _movable ? SideEffects{} : SideEffects::worst();
f.isMSize = false; f.isMSize = false;
f.literalArguments = _literalArguments; f.literalArguments = _literalArguments;

View File

@ -56,7 +56,13 @@ struct WasmDialect: public Dialect
private: private:
void addEthereumExternals(); void addEthereumExternals();
void addFunction(std::string _name, size_t _params, size_t _returns, bool _movable = true, bool _literalArguments = false); void addFunction(
std::string _name,
std::vector<YulString> _params,
std::vector<YulString> _returns,
bool _movable = true,
bool _literalArguments = false
);
std::map<YulString, BuiltinFunction> m_functions; std::map<YulString, BuiltinFunction> m_functions;
}; };