diff --git a/libyul/backends/wasm/WasmDialect.cpp b/libyul/backends/wasm/WasmDialect.cpp index fb230562e..8e0cba8f9 100644 --- a/libyul/backends/wasm/WasmDialect.cpp +++ b/libyul/backends/wasm/WasmDialect.cpp @@ -56,10 +56,16 @@ WasmDialect::WasmDialect(): addFunction("i64.eqz", 1, 1); m_functions["i64.eqz"_yulstring].returns.front() = "i32"_yulstring; + addFunction("i64.clz", 1, 1); + addFunction("i64.store", 2, 0, false); m_functions["i64.store"_yulstring].parameters.front() = "i32"_yulstring; m_functions["i64.store"_yulstring].sideEffects.invalidatesStorage = false; + addFunction("i64.store8", 2, 0, false); + m_functions["i64.store8"_yulstring].parameters.front() = "i32"_yulstring; + m_functions["i64.store8"_yulstring].sideEffects.invalidatesStorage = false; + addFunction("i64.load", 1, 1, false); m_functions["i64.load"_yulstring].parameters.front() = "i32"_yulstring; m_functions["i64.load"_yulstring].sideEffects.invalidatesStorage = false; diff --git a/test/tools/yulInterpreter/EWasmBuiltinInterpreter.cpp b/test/tools/yulInterpreter/EWasmBuiltinInterpreter.cpp index 9a8c89262..a35a6f491 100644 --- a/test/tools/yulInterpreter/EWasmBuiltinInterpreter.cpp +++ b/test/tools/yulInterpreter/EWasmBuiltinInterpreter.cpp @@ -49,6 +49,21 @@ void copyZeroExtended( _target[_targetOffset + i] = _sourceOffset + i < _source.size() ? _source[_sourceOffset + i] : 0; } +/// Count leading zeros for uint64 +uint64_t clz(uint64_t _v) +{ + if (_v == 0) + return 64; + + uint64_t r = 0; + while (!(_v & 0x8000000000000000)) + { + r += 1; + _v = _v << 1; + } + return r; +} + } using u512 = boost::multiprecision::number>; @@ -119,6 +134,8 @@ u256 EWasmBuiltinInterpreter::evalBuiltin(YulString _fun, vector const& _a return arg[0] != arg[1] ? 1 : 0; else if (_fun == "i64.eqz"_yulstring) return arg[0] == 0 ? 1 : 0; + else if (_fun == "i64.clz"_yulstring) + return clz(arg[0]); else if (_fun == "i64.lt_u"_yulstring) return arg[0] < arg[1] ? 1 : 0; else if (_fun == "i64.gt_u"_yulstring) @@ -133,6 +150,12 @@ u256 EWasmBuiltinInterpreter::evalBuiltin(YulString _fun, vector const& _a writeMemoryWord(arg[0], arg[1]); return 0; } + else if (_fun == "i64.store8"_yulstring) + { + accessMemory(arg[0], 1); + writeMemoryByte(arg[0], static_cast(arg[1] & 0xff)); + return 0; + } else if (_fun == "i64.load"_yulstring) { accessMemory(arg[0], 8); @@ -148,7 +171,7 @@ u256 EWasmBuiltinInterpreter::evalBuiltin(YulString _fun, vector const& _a // TODO this does not read the address, but is consistent with // EVM interpreter implementation. // If we take the address into account, this needs to use readAddress. - writeU128(arg[0], m_state.balance); + writeU128(arg[1], m_state.balance); return 0; } else if (_fun == "eth.getBlockHash"_yulstring) @@ -368,6 +391,11 @@ void EWasmBuiltinInterpreter::writeMemoryWord(uint64_t _offset, uint64_t _value) m_state.memory[_offset + i] = uint8_t((_value >> (i * 8)) & 0xff); } +void EWasmBuiltinInterpreter::writeMemoryByte(uint64_t _offset, uint8_t _value) +{ + m_state.memory[_offset] = _value; +} + void EWasmBuiltinInterpreter::writeU256(uint64_t _offset, u256 _value, size_t _croppedTo) { accessMemory(_offset, _croppedTo); diff --git a/test/tools/yulInterpreter/EWasmBuiltinInterpreter.h b/test/tools/yulInterpreter/EWasmBuiltinInterpreter.h index 8472b4a22..363c11f45 100644 --- a/test/tools/yulInterpreter/EWasmBuiltinInterpreter.h +++ b/test/tools/yulInterpreter/EWasmBuiltinInterpreter.h @@ -86,6 +86,9 @@ private: /// Writes a word to memory (little-endian) /// Does not adjust msize, use @a accessMemory for that void writeMemoryWord(uint64_t _offset, uint64_t _value); + /// Writes a byte to memory + /// Does not adjust msize, use @a accessMemory for that + void writeMemoryByte(uint64_t _offset, uint8_t _value); /// Helper for eth.* builtins. Writes to memory (big-endian) and always returns zero. void writeU256(uint64_t _offset, dev::u256 _value, size_t _croppedTo = 32);