Merge pull request #9367 from ethereum/wasm-dialect

Add ctz and popcnt to WasmDialect
This commit is contained in:
chriseth 2020-07-13 15:02:34 +02:00 committed by GitHub
commit 1d666335f8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 71 additions and 2 deletions

View File

@ -1,5 +1,8 @@
### 0.6.12 (unreleased)
Language Features:
* Wasm backend: Add ``i32.ctz``, ``i64.ctz``, ``i32.popcnt``, and ``i64.popcnt``.
Compiler Features:
* Code Generator: Evaluate ``keccak256`` of string literals at compile-time.

View File

@ -38,13 +38,18 @@ WasmDialect::WasmDialect()
"add",
"sub",
"mul",
// TODO: div_s
"div_u",
// TODO: rem_s
"rem_u",
"and",
"or",
"xor",
"shl",
// TODO: shr_s
"shr_u",
// TODO: rotl
// TODO: rotr
})
addFunction(t.str() + "." + name, {t, t}, {t});
@ -52,9 +57,13 @@ WasmDialect::WasmDialect()
for (auto const& name: {
"eq",
"ne",
// TODO: lt_s
"lt_u",
// TODO: gt_s
"gt_u",
// TODO: le_s
"le_u",
// TODO: ge_s
"ge_u"
})
addFunction(t.str() + "." + name, {t, t}, {i32});
@ -62,8 +71,13 @@ WasmDialect::WasmDialect()
addFunction("i32.eqz", {i32}, {i32});
addFunction("i64.eqz", {i64}, {i32});
addFunction("i32.clz", {i32}, {i32});
addFunction("i64.clz", {i64}, {i64});
for (auto t: types)
for (auto const& name: {
"clz",
"ctz",
"popcnt",
})
addFunction(t.str() + "." + name, {t}, {t});
addFunction("i32.wrap_i64", {i64}, {i32});
@ -73,6 +87,7 @@ WasmDialect::WasmDialect()
m_functions["i32.store"_yulstring].sideEffects.invalidatesStorage = false;
addFunction("i64.store", {i32, i64}, {}, false);
m_functions["i64.store"_yulstring].sideEffects.invalidatesStorage = false;
// TODO: add i32.store16, i64.store8, i64.store16, i64.store32
addFunction("i32.store8", {i32, i32}, {}, false);
m_functions["i32.store8"_yulstring].sideEffects.invalidatesStorage = false;
@ -89,6 +104,7 @@ WasmDialect::WasmDialect()
m_functions["i64.load"_yulstring].sideEffects.invalidatesMemory = false;
m_functions["i64.load"_yulstring].sideEffects.sideEffectFree = true;
m_functions["i64.load"_yulstring].sideEffects.sideEffectFreeIfNoMSize = true;
// TODO: add i32.load8, i32.load16, i64.load8, i64.load16, i64.load32
// Drop is actually overloaded for all types, but Yul does not support that.
// Because of that, we introduce "i32.drop" and "i64.drop".

View File

@ -67,6 +67,50 @@ uint64_t clz64(uint64_t _v)
return r;
}
/// Count trailing zeros for uint32. Following WebAssembly rules, it returns 32 for @a _v being zero.
/// NOTE: the ctz builtin of the compiler may or may not do this
uint32_t ctz32(uint32_t _v)
{
if (_v == 0)
return 32;
uint32_t r = 0;
while (!(_v & 1))
{
r++;
_v >>= 1;
}
return r;
}
/// Count trailing zeros for uint64. Following WebAssembly rules, it returns 64 for @a _v being zero.
/// NOTE: the ctz builtin of the compiler may or may not do this
uint64_t ctz64(uint64_t _v)
{
if (_v == 0)
return 64;
uint64_t r = 0;
while (!(_v & 1))
{
r++;
_v >>= 1;
}
return r;
}
/// Count number of bits set for uint64
uint64_t popcnt(uint64_t _v)
{
uint64_t r = 0;
while (_v)
{
r += (_v & 1);
_v >>= 1;
}
return r;
}
}
using u512 = boost::multiprecision::number<boost::multiprecision::cpp_int_backend<512, 256, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void>>;
@ -139,6 +183,10 @@ u256 EwasmBuiltinInterpreter::evalBuiltin(YulString _fun, vector<u256> const& _a
return clz64(arg[0] & uint32_t(-1)) - 32;
else if (_fun == "i64.clz"_yulstring)
return clz64(arg[0]);
else if (_fun == "i32.ctz"_yulstring)
return ctz32(uint32_t(arg[0] & uint32_t(-1)));
else if (_fun == "i64.ctz"_yulstring)
return ctz64(arg[0]);
string prefix = _fun.str();
string suffix;
@ -207,6 +255,8 @@ u256 EwasmBuiltinInterpreter::evalWasmBuiltin(string const& _fun, vector<Word> c
return arg[0] != arg[1] ? 1 : 0;
else if (_fun == "eqz")
return arg[0] == 0 ? 1 : 0;
else if (_fun == "popcnt")
return popcnt(arg[0]);
else if (_fun == "lt_u")
return arg[0] < arg[1] ? 1 : 0;
else if (_fun == "gt_u")