diff --git a/libyul/backends/wasm/polyfill/Conversion.yul b/libyul/backends/wasm/polyfill/Conversion.yul index 3168b80ca..17d205ddd 100644 --- a/libyul/backends/wasm/polyfill/Conversion.yul +++ b/libyul/backends/wasm/polyfill/Conversion.yul @@ -59,20 +59,21 @@ function u256_to_address(x1, x2, x3, x4) -> r1, r2, r3 { r3 := x4 } -function bswap16(x) -> y { - let hi := i64.and(i64.shl(x, 8), 0xff00) - let lo := i64.and(i64.shr_u(x, 8), 0xff) - y := i64.or(hi, lo) +function bswap16(x:i32) -> y:i32 { + let hi:i32 := i32.and(i32.shl(x, 8:i32), 0xff00:i32) + let lo:i32 := i32.and(i32.shr_u(x, 8:i32), 0xff:i32) + y := i32.or(hi, lo) } -function bswap32(x) -> y { - let hi := i64.shl(bswap16(x), 16) - let lo := bswap16(i64.shr_u(x, 16)) - y := i64.or(hi, lo) +function bswap32(x:i32) -> y:i32 { + let hi:i32 := i32.shl(bswap16(x), 16:i32) + let lo:i32 := bswap16(i32.shr_u(x, 16:i32)) + y := i32.or(hi, lo) } + function bswap64(x) -> y { - let hi := i64.shl(bswap32(x), 32) - let lo := bswap32(i64.shr_u(x, 32)) + let hi := i64.shl(i64.extend_i32_u(bswap32(i32.wrap_i64(x))), 32) + let lo := i64.extend_i32_u(bswap32(i32.wrap_i64(i64.shr_u(x, 32)))) y := i64.or(hi, lo) } diff --git a/libyul/backends/wasm/polyfill/Interface.yul b/libyul/backends/wasm/polyfill/Interface.yul index 6251409bf..9c5fb59b4 100644 --- a/libyul/backends/wasm/polyfill/Interface.yul +++ b/libyul/backends/wasm/polyfill/Interface.yul @@ -19,14 +19,15 @@ // NOTE: This file is used to generate `ewasmPolyfills/Interface.h`. function address() -> z1, z2, z3, z4 { - eth.getAddress(0:i32) - z1, z2, z3, z4 := mload_internal(0:i32) + eth.getAddress(12:i32) + z1, z2, z3, z4 := mload_address(0:i32) } function balance(x1, x2, x3, x4) -> z1, z2, z3, z4 { mstore_address(0:i32, x1, x2, x3, x4) - eth.getExternalBalance(12:i32, 48:i32) - z1, z2, z3, z4 := mload_internal(32:i32) + eth.getExternalBalance(12:i32, 32:i32) + z3 := i64.load(40:i32) + z4 := i64.load(32:i32) } function selfbalance() -> z1, z2, z3, z4 { @@ -40,13 +41,13 @@ function chainid() -> z1, z2, z3, z4 { } function origin() -> z1, z2, z3, z4 { - eth.getTxOrigin(0:i32) - z1, z2, z3, z4 := mload_internal(0:i32) + eth.getTxOrigin(12:i32) + z1, z2, z3, z4 := mload_address(0:i32) } function caller() -> z1, z2, z3, z4 { - eth.getCaller(0:i32) - z1, z2, z3, z4 := mload_internal(0:i32) + eth.getCaller(12:i32) + z1, z2, z3, z4 := mload_address(0:i32) } function callvalue() -> z1, z2, z3, z4 { @@ -155,8 +156,8 @@ function blockhash(x1, x2, x3, x4) -> z1, z2, z3, z4 { } function coinbase() -> z1, z2, z3, z4 { - eth.getBlockCoinbase(0:i32) - z1, z2, z3, z4 := mload_internal(0:i32) + eth.getBlockCoinbase(12:i32) + z1, z2, z3, z4 := mload_address(0:i32) } function timestamp() -> z1, z2, z3, z4 { @@ -180,34 +181,10 @@ function mload(x1, x2, x3, x4) -> z1, z2, z3, z4 { z1, z2, z3, z4 := mload_internal(to_internal_i32ptr(x1, x2, x3, x4)) } -function mload_internal(pos:i32) -> z1, z2, z3, z4 { - z1 := bswap64(i64.load(pos)) - z2 := bswap64(i64.load(i32.add(pos, 8:i32))) - z3 := bswap64(i64.load(i32.add(pos, 16:i32))) - z4 := bswap64(i64.load(i32.add(pos, 24:i32))) -} - function mstore(x1, x2, x3, x4, y1, y2, y3, y4) { mstore_internal(to_internal_i32ptr(x1, x2, x3, x4), y1, y2, y3, y4) } -function mstore_internal(pos:i32, y1, y2, y3, y4) { - i64.store(pos, bswap64(y1)) - i64.store(i32.add(pos, 8:i32), bswap64(y2)) - i64.store(i32.add(pos, 16:i32), bswap64(y3)) - i64.store(i32.add(pos, 24:i32), bswap64(y4)) -} - -function mstore_address(pos:i32, a1, a2, a3, a4) { - a1, a2, a3 := u256_to_address(a1, a2, a3, a4) - mstore_internal(pos, 0, a1, a2, a3) -} - -function mstore8(x1, x2, x3, x4, y1, y2, y3, y4) { - let v := u256_to_byte(y1, y2, y3, y4) - i64.store8(to_internal_i32ptr(x1, x2, x3, x4), v) -} - // Needed? function msize() -> z1, z2, z3, z4 { // TODO implement diff --git a/libyul/backends/wasm/polyfill/Memory.yul b/libyul/backends/wasm/polyfill/Memory.yul index aec8e86c6..410c42d8f 100644 --- a/libyul/backends/wasm/polyfill/Memory.yul +++ b/libyul/backends/wasm/polyfill/Memory.yul @@ -61,9 +61,49 @@ function memoryguard(x:i64) -> y1, y2, y3, y4 { y4 := x } +// Fill `length` bytes starting from `ptr` with `value`. function memset(ptr:i32, value:i32, length:i32) { for { let i:i32 := 0:i32 } i32.lt_u(i, length) { i := i32.add(i, 1:i32) } { i32.store8(i32.add(ptr, i), value) } -} \ No newline at end of file +} + +// Writes 256-bits from `pos`, but only set the bottom 160-bits. +function mstore_address(pos:i32, a1, a2, a3, a4) { + a1, a2, a3 := u256_to_address(a1, a2, a3, a4) + i64.store(pos, 0:i64) + i32.store(i32.add(pos, 8:i32), 0:i32) + i32.store(i32.add(pos, 12:i32), bswap32(i32.wrap_i64(a1))) + i64.store(i32.add(pos, 16:i32), bswap64(a2)) + i64.store(i32.add(pos, 24:i32), bswap64(a3)) +} + +// Reads 256-bits from `pos`, but only returns the bottom 160-bits. +function mload_address(pos:i32) -> z1, z2, z3, z4 { + z2 := i64.extend_i32_u(bswap32(i32.load(i32.add(pos, 12:i32)))) + z3 := bswap64(i64.load(i32.add(pos, 16:i32))) + z4 := bswap64(i64.load(i32.add(pos, 24:i32))) +} + +// Writes 256-bits from `pos`. +function mstore_internal(pos:i32, y1, y2, y3, y4) { + i64.store(pos, bswap64(y1)) + i64.store(i32.add(pos, 8:i32), bswap64(y2)) + i64.store(i32.add(pos, 16:i32), bswap64(y3)) + i64.store(i32.add(pos, 24:i32), bswap64(y4)) +} + +// Reads 256-bits from `pos`. +function mload_internal(pos:i32) -> z1, z2, z3, z4 { + z1 := bswap64(i64.load(pos)) + z2 := bswap64(i64.load(i32.add(pos, 8:i32))) + z3 := bswap64(i64.load(i32.add(pos, 16:i32))) + z4 := bswap64(i64.load(i32.add(pos, 24:i32))) +} + +// Stores one byte at position `x` of value `y`. +function mstore8(x1, x2, x3, x4, y1, y2, y3, y4) { + let v := u256_to_byte(y1, y2, y3, y4) + i64.store8(to_internal_i32ptr(x1, x2, x3, x4), v) +} diff --git a/test/libsolidity/semanticTests/builtinFunctions/smoke.sol b/test/libsolidity/semanticTests/builtinFunctions/smoke.sol new file mode 100644 index 000000000..e69de29bb