| // Copyright 2015 the V8 project authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include <stdint.h> |
| #include <stdlib.h> |
| #include <string.h> |
| |
| #include "src/assembler-inl.h" |
| #include "src/base/bits.h" |
| #include "src/objects-inl.h" |
| |
| #include "test/cctest/cctest.h" |
| #include "test/cctest/compiler/value-helper.h" |
| #include "test/cctest/wasm/wasm-run-utils.h" |
| #include "test/common/wasm/test-signatures.h" |
| #include "test/common/wasm/wasm-macro-gen.h" |
| |
| namespace v8 { |
| namespace internal { |
| namespace wasm { |
| namespace test_run_wasm_64 { |
| |
| // If the target architecture is 64-bit, enable all tests. |
| #if !V8_TARGET_ARCH_32_BIT || V8_TARGET_ARCH_X64 |
| #define WASM_64 1 |
| #else |
| #define WASM_64 0 |
| #endif |
| |
| // Can't bridge macro land with nested macros. |
| #if V8_TARGET_ARCH_MIPS |
| #define MIPS true |
| #else |
| #define MIPS false |
| #endif |
| |
| #define FOREACH_I64_OPERATOR(V) \ |
| V(DepthFirst, true) \ |
| V(I64Phi, true) \ |
| V(I64Const, true) \ |
| V(I64Return, true) \ |
| V(I64Param, true) \ |
| V(I64LoadStore, true) \ |
| V(I64Add, true) \ |
| V(I64Sub, true) \ |
| V(I64Mul, !MIPS) \ |
| V(I64DivS, true) \ |
| V(I64DivU, true) \ |
| V(I64RemS, true) \ |
| V(I64RemU, true) \ |
| V(I64And, true) \ |
| V(I64Ior, true) \ |
| V(I64Xor, true) \ |
| V(I64Shl, true) \ |
| V(I64ShrU, true) \ |
| V(I64ShrS, true) \ |
| V(I64Eq, true) \ |
| V(I64Ne, true) \ |
| V(I64LtS, true) \ |
| V(I64LeS, true) \ |
| V(I64LtU, true) \ |
| V(I64LeU, true) \ |
| V(I64GtS, true) \ |
| V(I64GeS, true) \ |
| V(I64GtU, true) \ |
| V(I64GeU, true) \ |
| V(I64Ctz, true) \ |
| V(I64Clz, true) \ |
| V(I64Popcnt, true) \ |
| V(I32ConvertI64, true) \ |
| V(I64SConvertF32, true) \ |
| V(I64SConvertF64, true) \ |
| V(I64UConvertF32, true) \ |
| V(I64UConvertF64, true) \ |
| V(I64SConvertI32, true) \ |
| V(I64UConvertI32, true) \ |
| V(F32SConvertI64, true) \ |
| V(F32UConvertI64, true) \ |
| V(F64SConvertI64, true) \ |
| V(F64UConvertI64, true) \ |
| V(F64ReinterpretI64, true) \ |
| V(I64ReinterpretF64, true) \ |
| V(I64Ror, true) \ |
| V(I64Rol, true) |
| |
| #define DECLARE_CONST(name, cond) static const bool kSupported_##name = cond; |
| FOREACH_I64_OPERATOR(DECLARE_CONST) |
| #undef DECLARE_CONST |
| |
| #undef FOREACH_I64_OPERATOR |
| |
| #define REQUIRE(name) \ |
| if (!WASM_64 && !kSupported_##name) return |
| |
| WASM_EXEC_TEST(I64Const) { |
| REQUIRE(I64Const); |
| WasmRunner<int64_t> r(execution_mode); |
| const int64_t kExpectedValue = 0x1122334455667788LL; |
| // return(kExpectedValue) |
| BUILD(r, WASM_I64V_9(kExpectedValue)); |
| CHECK_EQ(kExpectedValue, r.Call()); |
| } |
| |
| WASM_EXEC_TEST(I64Const_many) { |
| REQUIRE(I64Const); |
| int cntr = 0; |
| FOR_INT32_INPUTS(i) { |
| WasmRunner<int64_t> r(execution_mode); |
| const int64_t kExpectedValue = (static_cast<int64_t>(*i) << 32) | cntr; |
| // return(kExpectedValue) |
| BUILD(r, WASM_I64V(kExpectedValue)); |
| CHECK_EQ(kExpectedValue, r.Call()); |
| cntr++; |
| } |
| } |
| |
| WASM_EXEC_TEST(Return_I64) { |
| REQUIRE(I64Return); |
| WasmRunner<int64_t, int64_t> r(execution_mode); |
| |
| BUILD(r, WASM_RETURN1(WASM_GET_LOCAL(0))); |
| |
| FOR_INT64_INPUTS(i) { CHECK_EQ(*i, r.Call(*i)); } |
| } |
| |
| WASM_EXEC_TEST(I64Add) { |
| REQUIRE(I64Add); |
| WasmRunner<int64_t, int64_t, int64_t> r(execution_mode); |
| BUILD(r, WASM_I64_ADD(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))); |
| FOR_INT64_INPUTS(i) { |
| FOR_INT64_INPUTS(j) { CHECK_EQ(*i + *j, r.Call(*i, *j)); } |
| } |
| } |
| |
| // The i64 add and subtract regression tests need a 64-bit value with a non-zero |
| // upper half. This upper half was clobbering eax, leading to the function |
| // returning 1 rather than 0. |
| const int64_t kHasBit33On = 0x100000000; |
| |
| WASM_EXEC_TEST(Regress5800_Add) { |
| REQUIRE(I64Add); |
| WasmRunner<int32_t> r(execution_mode); |
| BUILD(r, WASM_BLOCK(WASM_BR_IF(0, WASM_I64_EQZ(WASM_I64_ADD( |
| WASM_I64V(0), WASM_I64V(kHasBit33On)))), |
| WASM_RETURN1(WASM_I32V(0))), |
| WASM_I32V(0)); |
| CHECK_EQ(0, r.Call()); |
| } |
| |
| WASM_EXEC_TEST(I64Sub) { |
| REQUIRE(I64Sub); |
| WasmRunner<int64_t, int64_t, int64_t> r(execution_mode); |
| BUILD(r, WASM_I64_SUB(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))); |
| FOR_INT64_INPUTS(i) { |
| FOR_INT64_INPUTS(j) { CHECK_EQ(*i - *j, r.Call(*i, *j)); } |
| } |
| } |
| |
| WASM_EXEC_TEST(Regress5800_Sub) { |
| REQUIRE(I64Sub); |
| WasmRunner<int32_t> r(execution_mode); |
| BUILD(r, WASM_BLOCK(WASM_BR_IF(0, WASM_I64_EQZ(WASM_I64_SUB( |
| WASM_I64V(0), WASM_I64V(kHasBit33On)))), |
| WASM_RETURN1(WASM_I32V(0))), |
| WASM_I32V(0)); |
| CHECK_EQ(0, r.Call()); |
| } |
| |
| WASM_EXEC_TEST(I64AddUseOnlyLowWord) { |
| REQUIRE(I64Add); |
| REQUIRE(I32ConvertI64); |
| WasmRunner<int32_t, int64_t, int64_t> r(execution_mode); |
| BUILD(r, WASM_I32_CONVERT_I64( |
| WASM_I64_ADD(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)))); |
| FOR_INT64_INPUTS(i) { |
| FOR_INT64_INPUTS(j) { |
| CHECK_EQ(static_cast<int32_t>(*i + *j), r.Call(*i, *j)); |
| } |
| } |
| } |
| |
| WASM_EXEC_TEST(I64SubUseOnlyLowWord) { |
| REQUIRE(I64Sub); |
| REQUIRE(I32ConvertI64); |
| WasmRunner<int32_t, int64_t, int64_t> r(execution_mode); |
| BUILD(r, WASM_I32_CONVERT_I64( |
| WASM_I64_SUB(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)))); |
| FOR_INT64_INPUTS(i) { |
| FOR_INT64_INPUTS(j) { |
| CHECK_EQ(static_cast<int32_t>(*i - *j), r.Call(*i, *j)); |
| } |
| } |
| } |
| |
| WASM_EXEC_TEST(I64MulUseOnlyLowWord) { |
| REQUIRE(I64Mul); |
| REQUIRE(I32ConvertI64); |
| WasmRunner<int32_t, int64_t, int64_t> r(execution_mode); |
| BUILD(r, WASM_I32_CONVERT_I64( |
| WASM_I64_MUL(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)))); |
| FOR_INT64_INPUTS(i) { |
| FOR_INT64_INPUTS(j) { |
| CHECK_EQ(static_cast<int32_t>(*i * *j), r.Call(*i, *j)); |
| } |
| } |
| } |
| |
| WASM_EXEC_TEST(I64ShlUseOnlyLowWord) { |
| REQUIRE(I64Shl); |
| REQUIRE(I32ConvertI64); |
| WasmRunner<int32_t, int64_t, int64_t> r(execution_mode); |
| BUILD(r, WASM_I32_CONVERT_I64( |
| WASM_I64_SHL(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)))); |
| FOR_INT64_INPUTS(i) { |
| FOR_INT64_INPUTS(j) { |
| int32_t expected = static_cast<int32_t>((*i) << (*j & 0x3F)); |
| CHECK_EQ(expected, r.Call(*i, *j)); |
| } |
| } |
| } |
| |
| WASM_EXEC_TEST(I64ShrUseOnlyLowWord) { |
| REQUIRE(I64ShrU); |
| REQUIRE(I32ConvertI64); |
| WasmRunner<int32_t, int64_t, int64_t> r(execution_mode); |
| BUILD(r, WASM_I32_CONVERT_I64( |
| WASM_I64_SHR(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)))); |
| FOR_UINT64_INPUTS(i) { |
| FOR_UINT64_INPUTS(j) { |
| int32_t expected = static_cast<int32_t>((*i) >> (*j & 0x3F)); |
| CHECK_EQ(expected, r.Call(*i, *j)); |
| } |
| } |
| } |
| |
| WASM_EXEC_TEST(I64SarUseOnlyLowWord) { |
| REQUIRE(I64ShrS); |
| REQUIRE(I32ConvertI64); |
| WasmRunner<int32_t, int64_t, int64_t> r(execution_mode); |
| BUILD(r, WASM_I32_CONVERT_I64( |
| WASM_I64_SAR(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)))); |
| FOR_INT64_INPUTS(i) { |
| FOR_INT64_INPUTS(j) { |
| int32_t expected = static_cast<int32_t>((*i) >> (*j & 0x3F)); |
| CHECK_EQ(expected, r.Call(*i, *j)); |
| } |
| } |
| } |
| |
| WASM_EXEC_TEST(I64DivS) { |
| REQUIRE(I64DivS); |
| WasmRunner<int64_t, int64_t, int64_t> r(execution_mode); |
| BUILD(r, WASM_I64_DIVS(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))); |
| FOR_INT64_INPUTS(i) { |
| FOR_INT64_INPUTS(j) { |
| if (*j == 0) { |
| CHECK_TRAP64(r.Call(*i, *j)); |
| } else if (*j == -1 && *i == std::numeric_limits<int64_t>::min()) { |
| CHECK_TRAP64(r.Call(*i, *j)); |
| } else { |
| CHECK_EQ(*i / *j, r.Call(*i, *j)); |
| } |
| } |
| } |
| } |
| |
| WASM_EXEC_TEST(I64DivS_Trap) { |
| REQUIRE(I64DivS); |
| WasmRunner<int64_t, int64_t, int64_t> r(execution_mode); |
| BUILD(r, WASM_I64_DIVS(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))); |
| CHECK_EQ(0, r.Call(int64_t{0}, int64_t{100})); |
| CHECK_TRAP64(r.Call(int64_t{100}, int64_t{0})); |
| CHECK_TRAP64(r.Call(int64_t{-1001}, int64_t{0})); |
| CHECK_TRAP64(r.Call(std::numeric_limits<int64_t>::min(), int64_t{-1})); |
| CHECK_TRAP64(r.Call(std::numeric_limits<int64_t>::min(), int64_t{0})); |
| } |
| |
| WASM_EXEC_TEST(I64DivS_Byzero_Const) { |
| REQUIRE(I64DivS); |
| for (int8_t denom = -2; denom < 8; denom++) { |
| WasmRunner<int64_t, int64_t> r(execution_mode); |
| BUILD(r, WASM_I64_DIVS(WASM_GET_LOCAL(0), WASM_I64V_1(denom))); |
| for (int64_t val = -7; val < 8; val++) { |
| if (denom == 0) { |
| CHECK_TRAP64(r.Call(val)); |
| } else { |
| CHECK_EQ(val / denom, r.Call(val)); |
| } |
| } |
| } |
| } |
| |
| WASM_EXEC_TEST(I64DivU) { |
| REQUIRE(I64DivU); |
| WasmRunner<uint64_t, uint64_t, uint64_t> r(execution_mode); |
| BUILD(r, WASM_I64_DIVU(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))); |
| FOR_UINT64_INPUTS(i) { |
| FOR_UINT64_INPUTS(j) { |
| if (*j == 0) { |
| CHECK_TRAP64(r.Call(*i, *j)); |
| } else { |
| CHECK_EQ(*i / *j, r.Call(*i, *j)); |
| } |
| } |
| } |
| } |
| |
| WASM_EXEC_TEST(I64DivU_Trap) { |
| REQUIRE(I64DivU); |
| WasmRunner<uint64_t, uint64_t, uint64_t> r(execution_mode); |
| BUILD(r, WASM_I64_DIVU(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))); |
| CHECK_EQ(0, r.Call(uint64_t{0}, uint64_t{100})); |
| CHECK_TRAP64(r.Call(uint64_t{100}, uint64_t{0})); |
| CHECK_TRAP64(r.Call(uint64_t{1001}, uint64_t{0})); |
| CHECK_TRAP64(r.Call(std::numeric_limits<uint64_t>::max(), uint64_t{0})); |
| } |
| |
| WASM_EXEC_TEST(I64DivU_Byzero_Const) { |
| REQUIRE(I64DivU); |
| for (uint64_t denom = 0xFFFFFFFFFFFFFFFE; denom < 8; denom++) { |
| WasmRunner<uint64_t, uint64_t> r(execution_mode); |
| BUILD(r, WASM_I64_DIVU(WASM_GET_LOCAL(0), WASM_I64V_1(denom))); |
| |
| for (uint64_t val = 0xFFFFFFFFFFFFFFF0; val < 8; val++) { |
| if (denom == 0) { |
| CHECK_TRAP64(r.Call(val)); |
| } else { |
| CHECK_EQ(val / denom, r.Call(val)); |
| } |
| } |
| } |
| } |
| |
| WASM_EXEC_TEST(I64RemS) { |
| REQUIRE(I64RemS); |
| WasmRunner<int64_t, int64_t, int64_t> r(execution_mode); |
| BUILD(r, WASM_I64_REMS(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))); |
| FOR_INT64_INPUTS(i) { |
| FOR_INT64_INPUTS(j) { |
| if (*j == 0) { |
| CHECK_TRAP64(r.Call(*i, *j)); |
| } else { |
| CHECK_EQ(*i % *j, r.Call(*i, *j)); |
| } |
| } |
| } |
| } |
| |
| WASM_EXEC_TEST(I64RemS_Trap) { |
| REQUIRE(I64RemS); |
| WasmRunner<int64_t, int64_t, int64_t> r(execution_mode); |
| BUILD(r, WASM_I64_REMS(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))); |
| CHECK_EQ(33, r.Call(int64_t{133}, int64_t{100})); |
| CHECK_EQ(0, r.Call(std::numeric_limits<int64_t>::min(), int64_t{-1})); |
| CHECK_TRAP64(r.Call(int64_t{100}, int64_t{0})); |
| CHECK_TRAP64(r.Call(int64_t{-1001}, int64_t{0})); |
| CHECK_TRAP64(r.Call(std::numeric_limits<int64_t>::min(), int64_t{0})); |
| } |
| |
| WASM_EXEC_TEST(I64RemU) { |
| REQUIRE(I64RemU); |
| WasmRunner<uint64_t, uint64_t, uint64_t> r(execution_mode); |
| BUILD(r, WASM_I64_REMU(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))); |
| FOR_UINT64_INPUTS(i) { |
| FOR_UINT64_INPUTS(j) { |
| if (*j == 0) { |
| CHECK_TRAP64(r.Call(*i, *j)); |
| } else { |
| CHECK_EQ(*i % *j, r.Call(*i, *j)); |
| } |
| } |
| } |
| } |
| |
| WASM_EXEC_TEST(I64RemU_Trap) { |
| REQUIRE(I64RemU); |
| WasmRunner<uint64_t, uint64_t, uint64_t> r(execution_mode); |
| BUILD(r, WASM_I64_REMU(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))); |
| CHECK_EQ(17, r.Call(uint64_t{217}, uint64_t{100})); |
| CHECK_TRAP64(r.Call(uint64_t{100}, uint64_t{0})); |
| CHECK_TRAP64(r.Call(uint64_t{1001}, uint64_t{0})); |
| CHECK_TRAP64(r.Call(std::numeric_limits<uint64_t>::max(), uint64_t{0})); |
| } |
| |
| WASM_EXEC_TEST(I64And) { |
| REQUIRE(I64And); |
| WasmRunner<int64_t, int64_t, int64_t> r(execution_mode); |
| BUILD(r, WASM_I64_AND(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))); |
| FOR_INT64_INPUTS(i) { |
| FOR_INT64_INPUTS(j) { CHECK_EQ((*i) & (*j), r.Call(*i, *j)); } |
| } |
| } |
| |
| WASM_EXEC_TEST(I64Ior) { |
| REQUIRE(I64Ior); |
| WasmRunner<int64_t, int64_t, int64_t> r(execution_mode); |
| BUILD(r, WASM_I64_IOR(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))); |
| FOR_INT64_INPUTS(i) { |
| FOR_INT64_INPUTS(j) { CHECK_EQ((*i) | (*j), r.Call(*i, *j)); } |
| } |
| } |
| |
| WASM_EXEC_TEST(I64Xor) { |
| REQUIRE(I64Xor); |
| WasmRunner<int64_t, int64_t, int64_t> r(execution_mode); |
| BUILD(r, WASM_I64_XOR(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))); |
| FOR_INT64_INPUTS(i) { |
| FOR_INT64_INPUTS(j) { CHECK_EQ((*i) ^ (*j), r.Call(*i, *j)); } |
| } |
| } |
| |
| WASM_EXEC_TEST(I64Shl) { |
| REQUIRE(I64Shl); |
| { |
| WasmRunner<uint64_t, uint64_t, uint64_t> r(execution_mode); |
| BUILD(r, WASM_I64_SHL(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))); |
| |
| FOR_UINT64_INPUTS(i) { |
| FOR_UINT64_INPUTS(j) { |
| uint64_t expected = (*i) << (*j & 0x3F); |
| CHECK_EQ(expected, r.Call(*i, *j)); |
| } |
| } |
| } |
| { |
| WasmRunner<uint64_t, int64_t> r(execution_mode); |
| BUILD(r, WASM_I64_SHL(WASM_GET_LOCAL(0), WASM_I64V_1(0))); |
| FOR_UINT64_INPUTS(i) { CHECK_EQ(*i << 0, r.Call(*i)); } |
| } |
| { |
| WasmRunner<uint64_t, int64_t> r(execution_mode); |
| BUILD(r, WASM_I64_SHL(WASM_GET_LOCAL(0), WASM_I64V_1(32))); |
| FOR_UINT64_INPUTS(i) { CHECK_EQ(*i << 32, r.Call(*i)); } |
| } |
| { |
| WasmRunner<uint64_t, int64_t> r(execution_mode); |
| BUILD(r, WASM_I64_SHL(WASM_GET_LOCAL(0), WASM_I64V_1(20))); |
| FOR_UINT64_INPUTS(i) { CHECK_EQ(*i << 20, r.Call(*i)); } |
| } |
| { |
| WasmRunner<uint64_t, int64_t> r(execution_mode); |
| BUILD(r, WASM_I64_SHL(WASM_GET_LOCAL(0), WASM_I64V_1(40))); |
| FOR_UINT64_INPUTS(i) { CHECK_EQ(*i << 40, r.Call(*i)); } |
| } |
| } |
| |
| WASM_EXEC_TEST(I64ShrU) { |
| REQUIRE(I64ShrU); |
| { |
| WasmRunner<uint64_t, uint64_t, uint64_t> r(execution_mode); |
| BUILD(r, WASM_I64_SHR(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))); |
| |
| FOR_UINT64_INPUTS(i) { |
| FOR_UINT64_INPUTS(j) { |
| uint64_t expected = (*i) >> (*j & 0x3F); |
| CHECK_EQ(expected, r.Call(*i, *j)); |
| } |
| } |
| } |
| { |
| WasmRunner<uint64_t, int64_t> r(execution_mode); |
| BUILD(r, WASM_I64_SHR(WASM_GET_LOCAL(0), WASM_I64V_1(0))); |
| FOR_UINT64_INPUTS(i) { CHECK_EQ(*i >> 0, r.Call(*i)); } |
| } |
| { |
| WasmRunner<uint64_t, int64_t> r(execution_mode); |
| BUILD(r, WASM_I64_SHR(WASM_GET_LOCAL(0), WASM_I64V_1(32))); |
| FOR_UINT64_INPUTS(i) { CHECK_EQ(*i >> 32, r.Call(*i)); } |
| } |
| { |
| WasmRunner<uint64_t, int64_t> r(execution_mode); |
| BUILD(r, WASM_I64_SHR(WASM_GET_LOCAL(0), WASM_I64V_1(20))); |
| FOR_UINT64_INPUTS(i) { CHECK_EQ(*i >> 20, r.Call(*i)); } |
| } |
| { |
| WasmRunner<uint64_t, int64_t> r(execution_mode); |
| BUILD(r, WASM_I64_SHR(WASM_GET_LOCAL(0), WASM_I64V_1(40))); |
| FOR_UINT64_INPUTS(i) { CHECK_EQ(*i >> 40, r.Call(*i)); } |
| } |
| } |
| |
| WASM_EXEC_TEST(I64ShrS) { |
| REQUIRE(I64ShrS); |
| { |
| WasmRunner<int64_t, int64_t, int64_t> r(execution_mode); |
| BUILD(r, WASM_I64_SAR(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))); |
| |
| FOR_INT64_INPUTS(i) { |
| FOR_INT64_INPUTS(j) { |
| int64_t expected = (*i) >> (*j & 0x3F); |
| CHECK_EQ(expected, r.Call(*i, *j)); |
| } |
| } |
| } |
| { |
| WasmRunner<int64_t, int64_t> r(execution_mode); |
| BUILD(r, WASM_I64_SAR(WASM_GET_LOCAL(0), WASM_I64V_1(0))); |
| FOR_INT64_INPUTS(i) { CHECK_EQ(*i >> 0, r.Call(*i)); } |
| } |
| { |
| WasmRunner<int64_t, int64_t> r(execution_mode); |
| BUILD(r, WASM_I64_SAR(WASM_GET_LOCAL(0), WASM_I64V_1(32))); |
| FOR_INT64_INPUTS(i) { CHECK_EQ(*i >> 32, r.Call(*i)); } |
| } |
| { |
| WasmRunner<int64_t, int64_t> r(execution_mode); |
| BUILD(r, WASM_I64_SAR(WASM_GET_LOCAL(0), WASM_I64V_1(20))); |
| FOR_INT64_INPUTS(i) { CHECK_EQ(*i >> 20, r.Call(*i)); } |
| } |
| { |
| WasmRunner<int64_t, int64_t> r(execution_mode); |
| BUILD(r, WASM_I64_SAR(WASM_GET_LOCAL(0), WASM_I64V_1(40))); |
| FOR_INT64_INPUTS(i) { CHECK_EQ(*i >> 40, r.Call(*i)); } |
| } |
| } |
| |
| WASM_EXEC_TEST(I64Eq) { |
| REQUIRE(I64Eq); |
| WasmRunner<int32_t, int64_t, int64_t> r(execution_mode); |
| BUILD(r, WASM_I64_EQ(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))); |
| FOR_INT64_INPUTS(i) { |
| FOR_INT64_INPUTS(j) { CHECK_EQ(*i == *j ? 1 : 0, r.Call(*i, *j)); } |
| } |
| } |
| |
| WASM_EXEC_TEST(I64Ne) { |
| REQUIRE(I64Ne); |
| WasmRunner<int32_t, int64_t, int64_t> r(execution_mode); |
| BUILD(r, WASM_I64_NE(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))); |
| FOR_INT64_INPUTS(i) { |
| FOR_INT64_INPUTS(j) { CHECK_EQ(*i != *j ? 1 : 0, r.Call(*i, *j)); } |
| } |
| } |
| |
| WASM_EXEC_TEST(I64LtS) { |
| REQUIRE(I64LtS); |
| WasmRunner<int32_t, int64_t, int64_t> r(execution_mode); |
| BUILD(r, WASM_I64_LTS(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))); |
| FOR_INT64_INPUTS(i) { |
| FOR_INT64_INPUTS(j) { CHECK_EQ(*i < *j ? 1 : 0, r.Call(*i, *j)); } |
| } |
| } |
| |
| WASM_EXEC_TEST(I64LeS) { |
| REQUIRE(I64LeS); |
| WasmRunner<int32_t, int64_t, int64_t> r(execution_mode); |
| BUILD(r, WASM_I64_LES(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))); |
| FOR_INT64_INPUTS(i) { |
| FOR_INT64_INPUTS(j) { CHECK_EQ(*i <= *j ? 1 : 0, r.Call(*i, *j)); } |
| } |
| } |
| |
| WASM_EXEC_TEST(I64LtU) { |
| REQUIRE(I64LtU); |
| WasmRunner<int32_t, int64_t, int64_t> r(execution_mode); |
| BUILD(r, WASM_I64_LTU(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))); |
| FOR_UINT64_INPUTS(i) { |
| FOR_UINT64_INPUTS(j) { CHECK_EQ(*i < *j ? 1 : 0, r.Call(*i, *j)); } |
| } |
| } |
| |
| WASM_EXEC_TEST(I64LeU) { |
| REQUIRE(I64LeU); |
| WasmRunner<int32_t, int64_t, int64_t> r(execution_mode); |
| BUILD(r, WASM_I64_LEU(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))); |
| FOR_UINT64_INPUTS(i) { |
| FOR_UINT64_INPUTS(j) { CHECK_EQ(*i <= *j ? 1 : 0, r.Call(*i, *j)); } |
| } |
| } |
| |
| WASM_EXEC_TEST(I64GtS) { |
| REQUIRE(I64GtS); |
| WasmRunner<int32_t, int64_t, int64_t> r(execution_mode); |
| BUILD(r, WASM_I64_GTS(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))); |
| FOR_INT64_INPUTS(i) { |
| FOR_INT64_INPUTS(j) { CHECK_EQ(*i > *j ? 1 : 0, r.Call(*i, *j)); } |
| } |
| } |
| |
| WASM_EXEC_TEST(I64GeS) { |
| REQUIRE(I64GeS); |
| WasmRunner<int32_t, int64_t, int64_t> r(execution_mode); |
| BUILD(r, WASM_I64_GES(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))); |
| FOR_INT64_INPUTS(i) { |
| FOR_INT64_INPUTS(j) { CHECK_EQ(*i >= *j ? 1 : 0, r.Call(*i, *j)); } |
| } |
| } |
| |
| WASM_EXEC_TEST(I64GtU) { |
| REQUIRE(I64GtU); |
| WasmRunner<int32_t, int64_t, int64_t> r(execution_mode); |
| BUILD(r, WASM_I64_GTU(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))); |
| FOR_UINT64_INPUTS(i) { |
| FOR_UINT64_INPUTS(j) { CHECK_EQ(*i > *j ? 1 : 0, r.Call(*i, *j)); } |
| } |
| } |
| |
| WASM_EXEC_TEST(I64GeU) { |
| REQUIRE(I64GeU); |
| WasmRunner<int32_t, int64_t, int64_t> r(execution_mode); |
| BUILD(r, WASM_I64_GEU(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))); |
| FOR_UINT64_INPUTS(i) { |
| FOR_UINT64_INPUTS(j) { CHECK_EQ(*i >= *j ? 1 : 0, r.Call(*i, *j)); } |
| } |
| } |
| |
| WASM_EXEC_TEST(I32ConvertI64) { |
| REQUIRE(I32ConvertI64); |
| FOR_INT64_INPUTS(i) { |
| WasmRunner<int32_t> r(execution_mode); |
| BUILD(r, WASM_I32_CONVERT_I64(WASM_I64V(*i))); |
| CHECK_EQ(static_cast<int32_t>(*i), r.Call()); |
| } |
| } |
| |
| WASM_EXEC_TEST(I64SConvertI32) { |
| REQUIRE(I64SConvertI32); |
| WasmRunner<int64_t, int32_t> r(execution_mode); |
| BUILD(r, WASM_I64_SCONVERT_I32(WASM_GET_LOCAL(0))); |
| FOR_INT32_INPUTS(i) { CHECK_EQ(static_cast<int64_t>(*i), r.Call(*i)); } |
| } |
| |
| WASM_EXEC_TEST(I64UConvertI32) { |
| REQUIRE(I64UConvertI32); |
| WasmRunner<int64_t, uint32_t> r(execution_mode); |
| BUILD(r, WASM_I64_UCONVERT_I32(WASM_GET_LOCAL(0))); |
| FOR_UINT32_INPUTS(i) { CHECK_EQ(static_cast<int64_t>(*i), r.Call(*i)); } |
| } |
| |
| WASM_EXEC_TEST(I64Popcnt) { |
| struct { |
| int64_t expected; |
| uint64_t input; |
| } values[] = {{64, 0xFFFFFFFFFFFFFFFF}, |
| {0, 0x0000000000000000}, |
| {2, 0x0000080000008000}, |
| {26, 0x1123456782345678}, |
| {38, 0xFFEDCBA09EDCBA09}}; |
| |
| WasmRunner<int64_t, uint64_t> r(execution_mode); |
| BUILD(r, WASM_I64_POPCNT(WASM_GET_LOCAL(0))); |
| for (size_t i = 0; i < arraysize(values); i++) { |
| CHECK_EQ(values[i].expected, r.Call(values[i].input)); |
| } |
| } |
| |
| WASM_EXEC_TEST(F32SConvertI64) { |
| REQUIRE(F32SConvertI64); |
| WasmRunner<float, int64_t> r(execution_mode); |
| BUILD(r, WASM_F32_SCONVERT_I64(WASM_GET_LOCAL(0))); |
| FOR_INT64_INPUTS(i) { CHECK_FLOAT_EQ(static_cast<float>(*i), r.Call(*i)); } |
| } |
| |
| WASM_EXEC_TEST(F32UConvertI64) { |
| REQUIRE(F32UConvertI64); |
| struct { |
| uint64_t input; |
| uint32_t expected; |
| } values[] = {{0x0, 0x0}, |
| {0x1, 0x3F800000}, |
| {0xFFFFFFFF, 0x4F800000}, |
| {0x1B09788B, 0x4DD84BC4}, |
| {0x4C5FCE8, 0x4C98BF9D}, |
| {0xCC0DE5BF, 0x4F4C0DE6}, |
| {0x2, 0x40000000}, |
| {0x3, 0x40400000}, |
| {0x4, 0x40800000}, |
| {0x5, 0x40A00000}, |
| {0x8, 0x41000000}, |
| {0x9, 0x41100000}, |
| {0xFFFFFFFFFFFFFFFF, 0x5F800000}, |
| {0xFFFFFFFFFFFFFFFE, 0x5F800000}, |
| {0xFFFFFFFFFFFFFFFD, 0x5F800000}, |
| {0x0, 0x0}, |
| {0x100000000, 0x4F800000}, |
| {0xFFFFFFFF00000000, 0x5F800000}, |
| {0x1B09788B00000000, 0x5DD84BC4}, |
| {0x4C5FCE800000000, 0x5C98BF9D}, |
| {0xCC0DE5BF00000000, 0x5F4C0DE6}, |
| {0x200000000, 0x50000000}, |
| {0x300000000, 0x50400000}, |
| {0x400000000, 0x50800000}, |
| {0x500000000, 0x50A00000}, |
| {0x800000000, 0x51000000}, |
| {0x900000000, 0x51100000}, |
| {0x273A798E187937A3, 0x5E1CE9E6}, |
| {0xECE3AF835495A16B, 0x5F6CE3B0}, |
| {0xB668ECC11223344, 0x5D3668ED}, |
| {0x9E, 0x431E0000}, |
| {0x43, 0x42860000}, |
| {0xAF73, 0x472F7300}, |
| {0x116B, 0x458B5800}, |
| {0x658ECC, 0x4ACB1D98}, |
| {0x2B3B4C, 0x4A2CED30}, |
| {0x88776655, 0x4F087766}, |
| {0x70000000, 0x4EE00000}, |
| {0x7200000, 0x4CE40000}, |
| {0x7FFFFFFF, 0x4F000000}, |
| {0x56123761, 0x4EAC246F}, |
| {0x7FFFFF00, 0x4EFFFFFE}, |
| {0x761C4761EEEEEEEE, 0x5EEC388F}, |
| {0x80000000EEEEEEEE, 0x5F000000}, |
| {0x88888888DDDDDDDD, 0x5F088889}, |
| {0xA0000000DDDDDDDD, 0x5F200000}, |
| {0xDDDDDDDDAAAAAAAA, 0x5F5DDDDE}, |
| {0xE0000000AAAAAAAA, 0x5F600000}, |
| {0xEEEEEEEEEEEEEEEE, 0x5F6EEEEF}, |
| {0xFFFFFFFDEEEEEEEE, 0x5F800000}, |
| {0xF0000000DDDDDDDD, 0x5F700000}, |
| {0x7FFFFFDDDDDDDD, 0x5B000000}, |
| {0x3FFFFFAAAAAAAA, 0x5A7FFFFF}, |
| {0x1FFFFFAAAAAAAA, 0x59FFFFFD}, |
| {0xFFFFF, 0x497FFFF0}, |
| {0x7FFFF, 0x48FFFFE0}, |
| {0x3FFFF, 0x487FFFC0}, |
| {0x1FFFF, 0x47FFFF80}, |
| {0xFFFF, 0x477FFF00}, |
| {0x7FFF, 0x46FFFE00}, |
| {0x3FFF, 0x467FFC00}, |
| {0x1FFF, 0x45FFF800}, |
| {0xFFF, 0x457FF000}, |
| {0x7FF, 0x44FFE000}, |
| {0x3FF, 0x447FC000}, |
| {0x1FF, 0x43FF8000}, |
| {0x3FFFFFFFFFFF, 0x56800000}, |
| {0x1FFFFFFFFFFF, 0x56000000}, |
| {0xFFFFFFFFFFF, 0x55800000}, |
| {0x7FFFFFFFFFF, 0x55000000}, |
| {0x3FFFFFFFFFF, 0x54800000}, |
| {0x1FFFFFFFFFF, 0x54000000}, |
| {0x8000008000000000, 0x5F000000}, |
| {0x8000008000000001, 0x5F000001}, |
| {0x8000000000000400, 0x5F000000}, |
| {0x8000000000000401, 0x5F000000}}; |
| WasmRunner<float, uint64_t> r(execution_mode); |
| BUILD(r, WASM_F32_UCONVERT_I64(WASM_GET_LOCAL(0))); |
| for (size_t i = 0; i < arraysize(values); i++) { |
| CHECK_EQ(bit_cast<float>(values[i].expected), r.Call(values[i].input)); |
| } |
| } |
| |
| WASM_EXEC_TEST(F64SConvertI64) { |
| REQUIRE(F64SConvertI64); |
| WasmRunner<double, int64_t> r(execution_mode); |
| BUILD(r, WASM_F64_SCONVERT_I64(WASM_GET_LOCAL(0))); |
| FOR_INT64_INPUTS(i) { CHECK_DOUBLE_EQ(static_cast<double>(*i), r.Call(*i)); } |
| } |
| |
| WASM_EXEC_TEST(F64UConvertI64) { |
| REQUIRE(F64UConvertI64); |
| struct { |
| uint64_t input; |
| uint64_t expected; |
| } values[] = {{0x0, 0x0}, |
| {0x1, 0x3FF0000000000000}, |
| {0xFFFFFFFF, 0x41EFFFFFFFE00000}, |
| {0x1B09788B, 0x41BB09788B000000}, |
| {0x4C5FCE8, 0x419317F3A0000000}, |
| {0xCC0DE5BF, 0x41E981BCB7E00000}, |
| {0x2, 0x4000000000000000}, |
| {0x3, 0x4008000000000000}, |
| {0x4, 0x4010000000000000}, |
| {0x5, 0x4014000000000000}, |
| {0x8, 0x4020000000000000}, |
| {0x9, 0x4022000000000000}, |
| {0xFFFFFFFFFFFFFFFF, 0x43F0000000000000}, |
| {0xFFFFFFFFFFFFFFFE, 0x43F0000000000000}, |
| {0xFFFFFFFFFFFFFFFD, 0x43F0000000000000}, |
| {0x100000000, 0x41F0000000000000}, |
| {0xFFFFFFFF00000000, 0x43EFFFFFFFE00000}, |
| {0x1B09788B00000000, 0x43BB09788B000000}, |
| {0x4C5FCE800000000, 0x439317F3A0000000}, |
| {0xCC0DE5BF00000000, 0x43E981BCB7E00000}, |
| {0x200000000, 0x4200000000000000}, |
| {0x300000000, 0x4208000000000000}, |
| {0x400000000, 0x4210000000000000}, |
| {0x500000000, 0x4214000000000000}, |
| {0x800000000, 0x4220000000000000}, |
| {0x900000000, 0x4222000000000000}, |
| {0x273A798E187937A3, 0x43C39D3CC70C3C9C}, |
| {0xECE3AF835495A16B, 0x43ED9C75F06A92B4}, |
| {0xB668ECC11223344, 0x43A6CD1D98224467}, |
| {0x9E, 0x4063C00000000000}, |
| {0x43, 0x4050C00000000000}, |
| {0xAF73, 0x40E5EE6000000000}, |
| {0x116B, 0x40B16B0000000000}, |
| {0x658ECC, 0x415963B300000000}, |
| {0x2B3B4C, 0x41459DA600000000}, |
| {0x88776655, 0x41E10EECCAA00000}, |
| {0x70000000, 0x41DC000000000000}, |
| {0x7200000, 0x419C800000000000}, |
| {0x7FFFFFFF, 0x41DFFFFFFFC00000}, |
| {0x56123761, 0x41D5848DD8400000}, |
| {0x7FFFFF00, 0x41DFFFFFC0000000}, |
| {0x761C4761EEEEEEEE, 0x43DD8711D87BBBBC}, |
| {0x80000000EEEEEEEE, 0x43E00000001DDDDE}, |
| {0x88888888DDDDDDDD, 0x43E11111111BBBBC}, |
| {0xA0000000DDDDDDDD, 0x43E40000001BBBBC}, |
| {0xDDDDDDDDAAAAAAAA, 0x43EBBBBBBBB55555}, |
| {0xE0000000AAAAAAAA, 0x43EC000000155555}, |
| {0xEEEEEEEEEEEEEEEE, 0x43EDDDDDDDDDDDDE}, |
| {0xFFFFFFFDEEEEEEEE, 0x43EFFFFFFFBDDDDE}, |
| {0xF0000000DDDDDDDD, 0x43EE0000001BBBBC}, |
| {0x7FFFFFDDDDDDDD, 0x435FFFFFF7777777}, |
| {0x3FFFFFAAAAAAAA, 0x434FFFFFD5555555}, |
| {0x1FFFFFAAAAAAAA, 0x433FFFFFAAAAAAAA}, |
| {0xFFFFF, 0x412FFFFE00000000}, |
| {0x7FFFF, 0x411FFFFC00000000}, |
| {0x3FFFF, 0x410FFFF800000000}, |
| {0x1FFFF, 0x40FFFFF000000000}, |
| {0xFFFF, 0x40EFFFE000000000}, |
| {0x7FFF, 0x40DFFFC000000000}, |
| {0x3FFF, 0x40CFFF8000000000}, |
| {0x1FFF, 0x40BFFF0000000000}, |
| {0xFFF, 0x40AFFE0000000000}, |
| {0x7FF, 0x409FFC0000000000}, |
| {0x3FF, 0x408FF80000000000}, |
| {0x1FF, 0x407FF00000000000}, |
| {0x3FFFFFFFFFFF, 0x42CFFFFFFFFFFF80}, |
| {0x1FFFFFFFFFFF, 0x42BFFFFFFFFFFF00}, |
| {0xFFFFFFFFFFF, 0x42AFFFFFFFFFFE00}, |
| {0x7FFFFFFFFFF, 0x429FFFFFFFFFFC00}, |
| {0x3FFFFFFFFFF, 0x428FFFFFFFFFF800}, |
| {0x1FFFFFFFFFF, 0x427FFFFFFFFFF000}, |
| {0x8000008000000000, 0x43E0000010000000}, |
| {0x8000008000000001, 0x43E0000010000000}, |
| {0x8000000000000400, 0x43E0000000000000}, |
| {0x8000000000000401, 0x43E0000000000001}}; |
| WasmRunner<double, uint64_t> r(execution_mode); |
| BUILD(r, WASM_F64_UCONVERT_I64(WASM_GET_LOCAL(0))); |
| for (size_t i = 0; i < arraysize(values); i++) { |
| CHECK_EQ(bit_cast<double>(values[i].expected), r.Call(values[i].input)); |
| } |
| } |
| |
| WASM_EXEC_TEST(I64SConvertF32a) { |
| WasmRunner<int64_t, float> r(execution_mode); |
| BUILD(r, WASM_I64_SCONVERT_F32(WASM_GET_LOCAL(0))); |
| |
| FOR_FLOAT32_INPUTS(i) { |
| if (*i < static_cast<float>(std::numeric_limits<int64_t>::max()) && |
| *i >= static_cast<float>(std::numeric_limits<int64_t>::min())) { |
| CHECK_EQ(static_cast<int64_t>(*i), r.Call(*i)); |
| } else { |
| CHECK_TRAP64(r.Call(*i)); |
| } |
| } |
| } |
| |
| WASM_EXEC_TEST(I64SConvertF64a) { |
| WasmRunner<int64_t, double> r(execution_mode); |
| BUILD(r, WASM_I64_SCONVERT_F64(WASM_GET_LOCAL(0))); |
| |
| FOR_FLOAT64_INPUTS(i) { |
| if (*i < static_cast<double>(std::numeric_limits<int64_t>::max()) && |
| *i >= static_cast<double>(std::numeric_limits<int64_t>::min())) { |
| CHECK_EQ(static_cast<int64_t>(*i), r.Call(*i)); |
| } else { |
| CHECK_TRAP64(r.Call(*i)); |
| } |
| } |
| } |
| |
| WASM_EXEC_TEST(I64UConvertF32a) { |
| WasmRunner<uint64_t, float> r(execution_mode); |
| BUILD(r, WASM_I64_UCONVERT_F32(WASM_GET_LOCAL(0))); |
| |
| FOR_FLOAT32_INPUTS(i) { |
| if (*i < static_cast<float>(std::numeric_limits<uint64_t>::max()) && |
| *i > -1) { |
| CHECK_EQ(static_cast<uint64_t>(*i), r.Call(*i)); |
| } else { |
| CHECK_TRAP64(r.Call(*i)); |
| } |
| } |
| } |
| |
| WASM_EXEC_TEST(I64UConvertF64a) { |
| WasmRunner<uint64_t, double> r(execution_mode); |
| BUILD(r, WASM_I64_UCONVERT_F64(WASM_GET_LOCAL(0))); |
| |
| FOR_FLOAT64_INPUTS(i) { |
| if (*i < static_cast<float>(std::numeric_limits<uint64_t>::max()) && |
| *i > -1) { |
| CHECK_EQ(static_cast<uint64_t>(*i), r.Call(*i)); |
| } else { |
| CHECK_TRAP64(r.Call(*i)); |
| } |
| } |
| } |
| |
| WASM_EXEC_TEST(CallI64Parameter) { |
| ValueType param_types[20]; |
| for (int i = 0; i < 20; i++) param_types[i] = kWasmI64; |
| param_types[3] = kWasmI32; |
| param_types[4] = kWasmI32; |
| FunctionSig sig(1, 19, param_types); |
| for (int i = 0; i < 19; i++) { |
| if (i == 2 || i == 3) continue; |
| WasmRunner<int32_t> r(execution_mode); |
| // Build the target function. |
| WasmFunctionCompiler& t = r.NewFunction(&sig); |
| BUILD(t, WASM_GET_LOCAL(i)); |
| |
| // Build the calling function. |
| BUILD( |
| r, |
| WASM_I32_CONVERT_I64(WASM_CALL_FUNCTION( |
| t.function_index(), WASM_I64V_9(0xBCD12340000000B), |
| WASM_I64V_9(0xBCD12340000000C), WASM_I32V_1(0xD), |
| WASM_I32_CONVERT_I64(WASM_I64V_9(0xBCD12340000000E)), |
| WASM_I64V_9(0xBCD12340000000F), WASM_I64V_10(0xBCD1234000000010), |
| WASM_I64V_10(0xBCD1234000000011), WASM_I64V_10(0xBCD1234000000012), |
| WASM_I64V_10(0xBCD1234000000013), WASM_I64V_10(0xBCD1234000000014), |
| WASM_I64V_10(0xBCD1234000000015), WASM_I64V_10(0xBCD1234000000016), |
| WASM_I64V_10(0xBCD1234000000017), WASM_I64V_10(0xBCD1234000000018), |
| WASM_I64V_10(0xBCD1234000000019), WASM_I64V_10(0xBCD123400000001A), |
| WASM_I64V_10(0xBCD123400000001B), WASM_I64V_10(0xBCD123400000001C), |
| WASM_I64V_10(0xBCD123400000001D)))); |
| |
| CHECK_EQ(i + 0xB, r.Call()); |
| } |
| } |
| |
| WASM_EXEC_TEST(CallI64Return) { |
| ValueType return_types[3]; // TODO(rossberg): support more in the future |
| for (int i = 0; i < 3; i++) return_types[i] = kWasmI64; |
| return_types[1] = kWasmI32; |
| FunctionSig sig(2, 1, return_types); |
| |
| WasmRunner<int64_t> r(execution_mode); |
| // Build the target function. |
| WasmFunctionCompiler& t = r.NewFunction(&sig); |
| BUILD(t, WASM_GET_LOCAL(0), WASM_I32V(7)); |
| |
| // Build the first calling function. |
| BUILD(r, WASM_CALL_FUNCTION(t.function_index(), WASM_I64V(0xBCD12340000000B)), |
| WASM_DROP); |
| |
| CHECK_EQ(0xBCD12340000000B, r.Call()); |
| } |
| |
| void TestI64Binop(WasmExecutionMode execution_mode, WasmOpcode opcode, |
| int64_t expected, int64_t a, int64_t b) { |
| { |
| WasmRunner<int64_t> r(execution_mode); |
| // return K op K |
| BUILD(r, WASM_BINOP(opcode, WASM_I64V(a), WASM_I64V(b))); |
| CHECK_EQ(expected, r.Call()); |
| } |
| { |
| WasmRunner<int64_t, int64_t, int64_t> r(execution_mode); |
| // return a op b |
| BUILD(r, WASM_BINOP(opcode, WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))); |
| CHECK_EQ(expected, r.Call(a, b)); |
| } |
| } |
| |
| void TestI64Cmp(WasmExecutionMode execution_mode, WasmOpcode opcode, |
| int64_t expected, int64_t a, int64_t b) { |
| { |
| WasmRunner<int32_t> r(execution_mode); |
| // return K op K |
| BUILD(r, WASM_BINOP(opcode, WASM_I64V(a), WASM_I64V(b))); |
| CHECK_EQ(expected, r.Call()); |
| } |
| { |
| WasmRunner<int32_t, int64_t, int64_t> r(execution_mode); |
| // return a op b |
| BUILD(r, WASM_BINOP(opcode, WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))); |
| CHECK_EQ(expected, r.Call(a, b)); |
| } |
| } |
| |
| #define TEST_I64_BINOP(name, expected, a, b) \ |
| do { \ |
| if (WASM_64 || kSupported_##name) \ |
| TestI64Binop(execution_mode, kExpr##name, expected, a, b); \ |
| } while (false) |
| |
| WASM_EXEC_TEST(I64Binops) { |
| TEST_I64_BINOP(I64Add, -5586332274295447011, 0x501B72EBABC26847, |
| 0x625DE9793D8F79D6); |
| TEST_I64_BINOP(I64Sub, 9001903251710731490, 0xF24FE6474640002E, |
| 0x7562B6F711991B4C); |
| TEST_I64_BINOP(I64Mul, -4569547818546064176, 0x231A263C2CBC6451, |
| 0xEAD44DE6BD3E23D0); |
| TEST_I64_BINOP(I64Mul, -25963122347507043, 0x4DA1FA47C9352B73, |
| 0x91FE82317AA035AF); |
| TEST_I64_BINOP(I64Mul, 7640290486138131960, 0x185731ABE8EEA47C, |
| 0x714EC59F1380D4C2); |
| TEST_I64_BINOP(I64DivS, -91517, 0x93B1190A34DE56A0, 0x00004D8F68863948); |
| TEST_I64_BINOP(I64DivU, 149016, 0xE15B3727E8A2080A, 0x0000631BFA72DB8B); |
| TEST_I64_BINOP(I64RemS, -664128064149968, 0x9A78B4E4FE708692, |
| 0x0003E0B6B3BE7609); |
| TEST_I64_BINOP(I64RemU, 1742040017332765, 0x0CE84708C6258C81, |
| 0x000A6FDE82016697); |
| TEST_I64_BINOP(I64And, 2531040582801836054, 0xAF257D1602644A16, |
| 0x33B290A91A10D997); |
| TEST_I64_BINOP(I64Ior, 8556201506536114940, 0x169D9BE7BD3F0A5C, |
| 0x66BCA28D77AF40E8); |
| TEST_I64_BINOP(I64Xor, -4605655183785456377, 0xB6EA20A5D48E85B8, |
| 0x76FF4DA6C80688BF); |
| TEST_I64_BINOP(I64Shl, -7240704056088331264, 0xEF4DC1ED030E8FFE, 9); |
| TEST_I64_BINOP(I64ShrU, 12500673744059159, 0xB1A52FA7DEEC5D14, 10); |
| TEST_I64_BINOP(I64ShrS, 1725103446999874, 0x3107C791461A112B, 11); |
| TEST_I64_BINOP(I64Ror, -8960135652432576946, 0x73418D1717E4E83A, 12); |
| TEST_I64_BINOP(I64Ror, 7617662827409989779, 0xEBFF67CF0C126D36, 13); |
| TEST_I64_BINOP(I64Rol, -2097714064174346012, 0x43938B8DB0B0F230, 14); |
| TEST_I64_BINOP(I64Rol, 8728493013947314237, 0xE07AF243AC4D219D, 15); |
| } |
| |
| #undef TEST_I64_BINOP |
| |
| #define TEST_I64_CMP(name, expected, a, b) \ |
| do { \ |
| if (WASM_64 || kSupported_##name) \ |
| TestI64Cmp(execution_mode, kExpr##name, expected, a, b); \ |
| } while (false) |
| |
| WASM_EXEC_TEST(I64Compare) { |
| TEST_I64_CMP(I64Eq, 0, 0xB915D8FA494064F0, 0x04D700B2536019A3); |
| TEST_I64_CMP(I64Ne, 1, 0xC2FAFAAAB0446CDC, 0x52A3328F780C97A3); |
| TEST_I64_CMP(I64LtS, 0, 0x673636E6306B0578, 0x028EC9ECA78F7227); |
| TEST_I64_CMP(I64LeS, 1, 0xAE5214114B86A0FA, 0x7C1D21DA3DFD0CCF); |
| TEST_I64_CMP(I64LtU, 0, 0x7D52166381EC1CE0, 0x59F4A6A9E78CD3D8); |
| TEST_I64_CMP(I64LeU, 1, 0xE4169A385C7EA0E0, 0xFBDBED2C8781E5BC); |
| TEST_I64_CMP(I64GtS, 0, 0x9D08FF8FB5F42E81, 0xD4E5C9D7FE09F621); |
| TEST_I64_CMP(I64GeS, 1, 0x78DA3B2F73264E0F, 0x6FE5E2A67C501CBE); |
| TEST_I64_CMP(I64GtU, 0, 0x8F691284E44F7DA9, 0xD5EA9BC1EE149192); |
| TEST_I64_CMP(I64GeU, 0, 0x0886A0C58C7AA224, 0x5DDBE5A81FD7EE47); |
| } |
| |
| #undef TEST_I64_CMP |
| |
| WASM_EXEC_TEST(I64Clz) { |
| REQUIRE(I64Clz); |
| struct { |
| int64_t expected; |
| uint64_t input; |
| } values[] = {{0, 0x8000100000000000}, {1, 0x4000050000000000}, |
| {2, 0x2000030000000000}, {3, 0x1000000300000000}, |
| {4, 0x0805000000000000}, {5, 0x0400600000000000}, |
| {6, 0x0200000000000000}, {7, 0x010000A000000000}, |
| {8, 0x00800C0000000000}, {9, 0x0040000000000000}, |
| {10, 0x0020000D00000000}, {11, 0x00100F0000000000}, |
| {12, 0x0008000000000000}, {13, 0x0004100000000000}, |
| {14, 0x0002002000000000}, {15, 0x0001030000000000}, |
| {16, 0x0000804000000000}, {17, 0x0000400500000000}, |
| {18, 0x0000205000000000}, {19, 0x0000170000000000}, |
| {20, 0x0000087000000000}, {21, 0x0000040500000000}, |
| {22, 0x0000020300000000}, {23, 0x0000010100000000}, |
| {24, 0x0000008900000000}, {25, 0x0000004100000000}, |
| {26, 0x0000002200000000}, {27, 0x0000001300000000}, |
| {28, 0x0000000800000000}, {29, 0x0000000400000000}, |
| {30, 0x0000000200000000}, {31, 0x0000000100000000}, |
| {32, 0x0000000080001000}, {33, 0x0000000040000500}, |
| {34, 0x0000000020000300}, {35, 0x0000000010000003}, |
| {36, 0x0000000008050000}, {37, 0x0000000004006000}, |
| {38, 0x0000000002000000}, {39, 0x00000000010000A0}, |
| {40, 0x0000000000800C00}, {41, 0x0000000000400000}, |
| {42, 0x000000000020000D}, {43, 0x0000000000100F00}, |
| {44, 0x0000000000080000}, {45, 0x0000000000041000}, |
| {46, 0x0000000000020020}, {47, 0x0000000000010300}, |
| {48, 0x0000000000008040}, {49, 0x0000000000004005}, |
| {50, 0x0000000000002050}, {51, 0x0000000000001700}, |
| {52, 0x0000000000000870}, {53, 0x0000000000000405}, |
| {54, 0x0000000000000203}, {55, 0x0000000000000101}, |
| {56, 0x0000000000000089}, {57, 0x0000000000000041}, |
| {58, 0x0000000000000022}, {59, 0x0000000000000013}, |
| {60, 0x0000000000000008}, {61, 0x0000000000000004}, |
| {62, 0x0000000000000002}, {63, 0x0000000000000001}, |
| {64, 0x0000000000000000}}; |
| |
| WasmRunner<int64_t, uint64_t> r(execution_mode); |
| BUILD(r, WASM_I64_CLZ(WASM_GET_LOCAL(0))); |
| for (size_t i = 0; i < arraysize(values); i++) { |
| CHECK_EQ(values[i].expected, r.Call(values[i].input)); |
| } |
| } |
| |
| WASM_EXEC_TEST(I64Ctz) { |
| REQUIRE(I64Ctz); |
| struct { |
| int64_t expected; |
| uint64_t input; |
| } values[] = {{64, 0x0000000000000000}, {63, 0x8000000000000000}, |
| {62, 0x4000000000000000}, {61, 0x2000000000000000}, |
| {60, 0x1000000000000000}, {59, 0xA800000000000000}, |
| {58, 0xF400000000000000}, {57, 0x6200000000000000}, |
| {56, 0x9100000000000000}, {55, 0xCD80000000000000}, |
| {54, 0x0940000000000000}, {53, 0xAF20000000000000}, |
| {52, 0xAC10000000000000}, {51, 0xE0B8000000000000}, |
| {50, 0x9CE4000000000000}, {49, 0xC792000000000000}, |
| {48, 0xB8F1000000000000}, {47, 0x3B9F800000000000}, |
| {46, 0xDB4C400000000000}, {45, 0xE9A3200000000000}, |
| {44, 0xFCA6100000000000}, {43, 0x6C8A780000000000}, |
| {42, 0x8CE5A40000000000}, {41, 0xCB7D020000000000}, |
| {40, 0xCB4DC10000000000}, {39, 0xDFBEC58000000000}, |
| {38, 0x27A9DB4000000000}, {37, 0xDE3BCB2000000000}, |
| {36, 0xD7E8A61000000000}, {35, 0x9AFDBC8800000000}, |
| {34, 0x9AFDBC8400000000}, {33, 0x9AFDBC8200000000}, |
| {32, 0x9AFDBC8100000000}, {31, 0x0000000080000000}, |
| {30, 0x0000000040000000}, {29, 0x0000000020000000}, |
| {28, 0x0000000010000000}, {27, 0x00000000A8000000}, |
| {26, 0x00000000F4000000}, {25, 0x0000000062000000}, |
| {24, 0x0000000091000000}, {23, 0x00000000CD800000}, |
| {22, 0x0000000009400000}, {21, 0x00000000AF200000}, |
| {20, 0x00000000AC100000}, {19, 0x00000000E0B80000}, |
| {18, 0x000000009CE40000}, {17, 0x00000000C7920000}, |
| {16, 0x00000000B8F10000}, {15, 0x000000003B9F8000}, |
| {14, 0x00000000DB4C4000}, {13, 0x00000000E9A32000}, |
| {12, 0x00000000FCA61000}, {11, 0x000000006C8A7800}, |
| {10, 0x000000008CE5A400}, {9, 0x00000000CB7D0200}, |
| {8, 0x00000000CB4DC100}, {7, 0x00000000DFBEC580}, |
| {6, 0x0000000027A9DB40}, {5, 0x00000000DE3BCB20}, |
| {4, 0x00000000D7E8A610}, {3, 0x000000009AFDBC88}, |
| {2, 0x000000009AFDBC84}, {1, 0x000000009AFDBC82}, |
| {0, 0x000000009AFDBC81}}; |
| |
| WasmRunner<int64_t, uint64_t> r(execution_mode); |
| BUILD(r, WASM_I64_CTZ(WASM_GET_LOCAL(0))); |
| for (size_t i = 0; i < arraysize(values); i++) { |
| CHECK_EQ(values[i].expected, r.Call(values[i].input)); |
| } |
| } |
| |
| WASM_EXEC_TEST(I64Popcnt2) { |
| REQUIRE(I64Popcnt); |
| struct { |
| int64_t expected; |
| uint64_t input; |
| } values[] = {{64, 0xFFFFFFFFFFFFFFFF}, |
| {0, 0x0000000000000000}, |
| {2, 0x0000080000008000}, |
| {26, 0x1123456782345678}, |
| {38, 0xFFEDCBA09EDCBA09}}; |
| |
| WasmRunner<int64_t, uint64_t> r(execution_mode); |
| BUILD(r, WASM_I64_POPCNT(WASM_GET_LOCAL(0))); |
| for (size_t i = 0; i < arraysize(values); i++) { |
| CHECK_EQ(values[i].expected, r.Call(values[i].input)); |
| } |
| } |
| |
| // Test the WasmRunner with an Int64 return value and different numbers of |
| // Int64 parameters. |
| WASM_EXEC_TEST(I64WasmRunner) { |
| REQUIRE(I64Param); |
| REQUIRE(I64Xor); |
| {FOR_INT64_INPUTS(i){WasmRunner<int64_t> r(execution_mode); |
| BUILD(r, WASM_I64V(*i)); |
| CHECK_EQ(*i, r.Call()); |
| } |
| } |
| { |
| WasmRunner<int64_t, int64_t> r(execution_mode); |
| BUILD(r, WASM_GET_LOCAL(0)); |
| FOR_INT64_INPUTS(i) { CHECK_EQ(*i, r.Call(*i)); } |
| } |
| { |
| WasmRunner<int64_t, int64_t, int64_t> r(execution_mode); |
| BUILD(r, WASM_I64_XOR(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))); |
| FOR_INT64_INPUTS(i) { |
| FOR_INT64_INPUTS(j) { CHECK_EQ(*i ^ *j, r.Call(*i, *j)); } |
| } |
| } |
| { |
| WasmRunner<int64_t, int64_t, int64_t, int64_t> r(execution_mode); |
| BUILD(r, WASM_I64_XOR(WASM_GET_LOCAL(0), |
| WASM_I64_XOR(WASM_GET_LOCAL(1), WASM_GET_LOCAL(2)))); |
| FOR_INT64_INPUTS(i) { |
| FOR_INT64_INPUTS(j) { |
| CHECK_EQ(*i ^ *j ^ *j, r.Call(*i, *j, *j)); |
| CHECK_EQ(*j ^ *i ^ *j, r.Call(*j, *i, *j)); |
| CHECK_EQ(*j ^ *j ^ *i, r.Call(*j, *j, *i)); |
| } |
| } |
| } |
| { |
| WasmRunner<int64_t, int64_t, int64_t, int64_t, int64_t> r(execution_mode); |
| BUILD(r, WASM_I64_XOR(WASM_GET_LOCAL(0), |
| WASM_I64_XOR(WASM_GET_LOCAL(1), |
| WASM_I64_XOR(WASM_GET_LOCAL(2), |
| WASM_GET_LOCAL(3))))); |
| FOR_INT64_INPUTS(i) { |
| FOR_INT64_INPUTS(j) { |
| CHECK_EQ(*i ^ *j ^ *j ^ *j, r.Call(*i, *j, *j, *j)); |
| CHECK_EQ(*j ^ *i ^ *j ^ *j, r.Call(*j, *i, *j, *j)); |
| CHECK_EQ(*j ^ *j ^ *i ^ *j, r.Call(*j, *j, *i, *j)); |
| CHECK_EQ(*j ^ *j ^ *j ^ *i, r.Call(*j, *j, *j, *i)); |
| } |
| } |
| } |
| } |
| |
| WASM_EXEC_TEST(Call_Int64Sub) { |
| REQUIRE(I64Sub); |
| WasmRunner<int64_t, int64_t, int64_t> r(execution_mode); |
| // Build the target function. |
| TestSignatures sigs; |
| WasmFunctionCompiler& t = r.NewFunction(sigs.l_ll()); |
| BUILD(t, WASM_I64_SUB(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))); |
| |
| // Build the caller function. |
| BUILD(r, WASM_CALL_FUNCTION(t.function_index(), WASM_GET_LOCAL(0), |
| WASM_GET_LOCAL(1))); |
| |
| FOR_INT32_INPUTS(i) { |
| FOR_INT32_INPUTS(j) { |
| int64_t a = static_cast<int64_t>(*i) << 32 | |
| (static_cast<int64_t>(*j) | 0xFFFFFFFF); |
| int64_t b = static_cast<int64_t>(*j) << 32 | |
| (static_cast<int64_t>(*i) | 0xFFFFFFFF); |
| |
| int64_t expected = static_cast<int64_t>(static_cast<uint64_t>(a) - |
| static_cast<uint64_t>(b)); |
| CHECK_EQ(expected, r.Call(a, b)); |
| } |
| } |
| } |
| |
| WASM_EXEC_TEST(LoadStoreI64_sx) { |
| REQUIRE(I64LoadStore); |
| REQUIRE(DepthFirst); |
| byte loads[] = {kExprI64LoadMem8S, kExprI64LoadMem16S, kExprI64LoadMem32S, |
| kExprI64LoadMem}; |
| |
| for (size_t m = 0; m < arraysize(loads); m++) { |
| WasmRunner<int64_t> r(execution_mode); |
| byte* memory = r.builder().AddMemoryElems<byte>(16); |
| |
| byte code[] = { |
| kExprI32Const, 8, // -- |
| kExprI32Const, 0, // -- |
| loads[m], // -- |
| ZERO_ALIGNMENT, // -- |
| ZERO_OFFSET, // -- |
| kExprI64StoreMem, // -- |
| ZERO_ALIGNMENT, // -- |
| ZERO_OFFSET, // -- |
| kExprI32Const, 0, // -- |
| loads[m], // -- |
| ZERO_ALIGNMENT, // -- |
| ZERO_OFFSET, // -- |
| }; |
| |
| r.Build(code, code + arraysize(code)); |
| |
| // Try a bunch of different negative values. |
| for (int i = -1; i >= -128; i -= 11) { |
| int size = 1 << m; |
| r.builder().BlankMemory(); |
| memory[size - 1] = static_cast<byte>(i); // set the high order byte. |
| |
| int64_t expected = static_cast<int64_t>(i) << ((size - 1) * 8); |
| |
| CHECK_EQ(expected, r.Call()); |
| CHECK_EQ(static_cast<byte>(i), memory[8 + size - 1]); |
| for (int j = size; j < 8; j++) { |
| CHECK_EQ(255, memory[8 + j]); |
| } |
| } |
| } |
| } |
| |
| WASM_EXEC_TEST(I64SConvertF32b) { |
| REQUIRE(I64SConvertF32); |
| WasmRunner<int64_t, float> r(execution_mode); |
| BUILD(r, WASM_I64_SCONVERT_F32(WASM_GET_LOCAL(0))); |
| |
| FOR_FLOAT32_INPUTS(i) { |
| if (*i < static_cast<float>(INT64_MAX) && |
| *i >= static_cast<float>(INT64_MIN)) { |
| CHECK_EQ(static_cast<int64_t>(*i), r.Call(*i)); |
| } else { |
| CHECK_TRAP64(r.Call(*i)); |
| } |
| } |
| } |
| |
| WASM_EXEC_TEST(I64SConvertF64b) { |
| REQUIRE(I64SConvertF64); |
| WasmRunner<int64_t, double> r(execution_mode); |
| BUILD(r, WASM_I64_SCONVERT_F64(WASM_GET_LOCAL(0))); |
| |
| FOR_FLOAT64_INPUTS(i) { |
| if (*i < static_cast<double>(INT64_MAX) && |
| *i >= static_cast<double>(INT64_MIN)) { |
| CHECK_EQ(static_cast<int64_t>(*i), r.Call(*i)); |
| } else { |
| CHECK_TRAP64(r.Call(*i)); |
| } |
| } |
| } |
| |
| WASM_EXEC_TEST(I64UConvertF32b) { |
| REQUIRE(I64UConvertF32); |
| WasmRunner<uint64_t, float> r(execution_mode); |
| BUILD(r, WASM_I64_UCONVERT_F32(WASM_GET_LOCAL(0))); |
| |
| FOR_FLOAT32_INPUTS(i) { |
| if (*i < static_cast<float>(UINT64_MAX) && *i > -1) { |
| CHECK_EQ(static_cast<uint64_t>(*i), r.Call(*i)); |
| } else { |
| CHECK_TRAP64(r.Call(*i)); |
| } |
| } |
| } |
| |
| WASM_EXEC_TEST(I64UConvertF64b) { |
| REQUIRE(I64UConvertF64); |
| WasmRunner<uint64_t, double> r(execution_mode); |
| BUILD(r, WASM_I64_UCONVERT_F64(WASM_GET_LOCAL(0))); |
| |
| FOR_FLOAT64_INPUTS(i) { |
| if (*i < static_cast<float>(UINT64_MAX) && *i > -1) { |
| CHECK_EQ(static_cast<uint64_t>(*i), r.Call(*i)); |
| } else { |
| CHECK_TRAP64(r.Call(*i)); |
| } |
| } |
| } |
| |
| WASM_EXEC_TEST(I64ReinterpretF64) { |
| REQUIRE(I64ReinterpretF64); |
| WasmRunner<int64_t> r(execution_mode); |
| int64_t* memory = r.builder().AddMemoryElems<int64_t>(8); |
| |
| BUILD(r, WASM_I64_REINTERPRET_F64( |
| WASM_LOAD_MEM(MachineType::Float64(), WASM_ZERO))); |
| |
| FOR_INT32_INPUTS(i) { |
| int64_t expected = static_cast<int64_t>(*i) * 0x300010001; |
| r.builder().WriteMemory(&memory[0], expected); |
| CHECK_EQ(expected, r.Call()); |
| } |
| } |
| |
| WASM_EXEC_TEST(SignallingNanSurvivesI64ReinterpretF64) { |
| REQUIRE(I64ReinterpretF64); |
| WasmRunner<int64_t> r(execution_mode); |
| BUILD(r, WASM_I64_REINTERPRET_F64(WASM_SEQ(kExprF64Const, 0x00, 0x00, 0x00, |
| 0x00, 0x00, 0x00, 0xF4, 0x7F))); |
| |
| // This is a signalling nan. |
| CHECK_EQ(0x7FF4000000000000, r.Call()); |
| } |
| |
| WASM_EXEC_TEST(F64ReinterpretI64) { |
| REQUIRE(F64ReinterpretI64); |
| WasmRunner<int64_t, int64_t> r(execution_mode); |
| int64_t* memory = r.builder().AddMemoryElems<int64_t>(8); |
| |
| BUILD(r, WASM_STORE_MEM(MachineType::Float64(), WASM_ZERO, |
| WASM_F64_REINTERPRET_I64(WASM_GET_LOCAL(0))), |
| WASM_GET_LOCAL(0)); |
| |
| FOR_INT32_INPUTS(i) { |
| int64_t expected = static_cast<int64_t>(*i) * 0x300010001; |
| CHECK_EQ(expected, r.Call(expected)); |
| CHECK_EQ(expected, r.builder().ReadMemory<int64_t>(&memory[0])); |
| } |
| } |
| |
| WASM_EXEC_TEST(LoadMemI64) { |
| REQUIRE(I64LoadStore); |
| WasmRunner<int64_t> r(execution_mode); |
| int64_t* memory = r.builder().AddMemoryElems<int64_t>(8); |
| r.builder().RandomizeMemory(1111); |
| |
| BUILD(r, WASM_LOAD_MEM(MachineType::Int64(), WASM_ZERO)); |
| |
| r.builder().WriteMemory<int64_t>(&memory[0], 0x1ABBCCDD00112233LL); |
| CHECK_EQ(0x1ABBCCDD00112233LL, r.Call()); |
| |
| r.builder().WriteMemory<int64_t>(&memory[0], 0x33AABBCCDD001122LL); |
| CHECK_EQ(0x33AABBCCDD001122LL, r.Call()); |
| |
| r.builder().WriteMemory<int64_t>(&memory[0], 77777777); |
| CHECK_EQ(77777777, r.Call()); |
| } |
| |
| WASM_EXEC_TEST(LoadMemI64_alignment) { |
| REQUIRE(I64LoadStore); |
| for (byte alignment = 0; alignment <= 3; alignment++) { |
| WasmRunner<int64_t> r(execution_mode); |
| int64_t* memory = r.builder().AddMemoryElems<int64_t>(8); |
| r.builder().RandomizeMemory(1111); |
| |
| BUILD(r, |
| WASM_LOAD_MEM_ALIGNMENT(MachineType::Int64(), WASM_ZERO, alignment)); |
| |
| r.builder().WriteMemory<int64_t>(&memory[0], 0x1ABBCCDD00112233LL); |
| CHECK_EQ(0x1ABBCCDD00112233LL, r.Call()); |
| |
| r.builder().WriteMemory<int64_t>(&memory[0], 0x33AABBCCDD001122LL); |
| CHECK_EQ(0x33AABBCCDD001122LL, r.Call()); |
| |
| r.builder().WriteMemory<int64_t>(&memory[0], 77777777); |
| CHECK_EQ(77777777, r.Call()); |
| } |
| } |
| |
| WASM_EXEC_TEST(MemI64_Sum) { |
| REQUIRE(I64LoadStore); |
| REQUIRE(I64Add); |
| REQUIRE(I64Sub); |
| REQUIRE(I64Phi); |
| const int kNumElems = 20; |
| WasmRunner<uint64_t, int32_t> r(execution_mode); |
| uint64_t* memory = r.builder().AddMemoryElems<uint64_t>(kNumElems); |
| const byte kSum = r.AllocateLocal(kWasmI64); |
| |
| BUILD(r, WASM_WHILE( |
| WASM_GET_LOCAL(0), |
| WASM_BLOCK( |
| WASM_SET_LOCAL( |
| kSum, WASM_I64_ADD(WASM_GET_LOCAL(kSum), |
| WASM_LOAD_MEM(MachineType::Int64(), |
| WASM_GET_LOCAL(0)))), |
| WASM_SET_LOCAL( |
| 0, WASM_I32_SUB(WASM_GET_LOCAL(0), WASM_I32V_1(8))))), |
| WASM_GET_LOCAL(1)); |
| |
| // Run 4 trials. |
| for (int i = 0; i < 3; i++) { |
| r.builder().RandomizeMemory(i * 33); |
| uint64_t expected = 0; |
| for (size_t j = kNumElems - 1; j > 0; j--) { |
| expected += r.builder().ReadMemory(&memory[j]); |
| } |
| uint64_t result = r.Call(8 * (kNumElems - 1)); |
| CHECK_EQ(expected, result); |
| } |
| } |
| |
| WASM_EXEC_TEST(StoreMemI64_alignment) { |
| const int64_t kWritten = 0x12345678ABCD0011ll; |
| |
| for (byte i = 0; i <= 3; i++) { |
| WasmRunner<int64_t, int64_t> r(execution_mode); |
| int64_t* memory = r.builder().AddMemoryElems<int64_t>(4); |
| BUILD(r, WASM_STORE_MEM_ALIGNMENT(MachineType::Int64(), WASM_ZERO, i, |
| WASM_GET_LOCAL(0)), |
| WASM_GET_LOCAL(0)); |
| r.builder().RandomizeMemory(1111); |
| r.builder().WriteMemory<int64_t>(&memory[0], 0); |
| |
| CHECK_EQ(kWritten, r.Call(kWritten)); |
| CHECK_EQ(kWritten, r.builder().ReadMemory(&memory[0])); |
| } |
| } |
| |
| WASM_EXEC_TEST(I64Global) { |
| REQUIRE(I64LoadStore); |
| REQUIRE(I64SConvertI32); |
| REQUIRE(I64And); |
| REQUIRE(DepthFirst); |
| WasmRunner<int32_t, int32_t> r(execution_mode); |
| int64_t* global = r.builder().AddGlobal<int64_t>(); |
| // global = global + p0 |
| BUILD(r, WASM_SET_GLOBAL( |
| 0, WASM_I64_AND(WASM_GET_GLOBAL(0), |
| WASM_I64_SCONVERT_I32(WASM_GET_LOCAL(0)))), |
| WASM_ZERO); |
| |
| r.builder().WriteMemory<int64_t>(global, 0xFFFFFFFFFFFFFFFFLL); |
| for (int i = 9; i < 444444; i += 111111) { |
| int64_t expected = *global & i; |
| r.Call(i); |
| CHECK_EQ(expected, *global); |
| } |
| } |
| |
| WASM_EXEC_TEST(I64Eqz) { |
| REQUIRE(I64Eq); |
| |
| WasmRunner<int32_t, int64_t> r(execution_mode); |
| BUILD(r, WASM_I64_EQZ(WASM_GET_LOCAL(0))); |
| |
| FOR_INT64_INPUTS(i) { |
| int32_t result = *i == 0 ? 1 : 0; |
| CHECK_EQ(result, r.Call(*i)); |
| } |
| } |
| |
| WASM_EXEC_TEST(I64Ror) { |
| REQUIRE(I64Ror); |
| WasmRunner<int64_t, int64_t, int64_t> r(execution_mode); |
| BUILD(r, WASM_I64_ROR(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))); |
| |
| FOR_UINT64_INPUTS(i) { |
| FOR_UINT64_INPUTS(j) { |
| int64_t expected = base::bits::RotateRight64(*i, *j & 0x3F); |
| CHECK_EQ(expected, r.Call(*i, *j)); |
| } |
| } |
| } |
| |
| WASM_EXEC_TEST(I64Rol) { |
| REQUIRE(I64Rol); |
| WasmRunner<int64_t, int64_t, int64_t> r(execution_mode); |
| BUILD(r, WASM_I64_ROL(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))); |
| |
| FOR_UINT64_INPUTS(i) { |
| FOR_UINT64_INPUTS(j) { |
| int64_t expected = base::bits::RotateLeft64(*i, *j & 0x3F); |
| CHECK_EQ(expected, r.Call(*i, *j)); |
| } |
| } |
| } |
| |
| WASM_EXEC_TEST(StoreMem_offset_oob_i64) { |
| // TODO(eholk): Fix this test for the trap handler. |
| if (trap_handler::IsTrapHandlerEnabled()) return; |
| static const MachineType machineTypes[] = { |
| MachineType::Int8(), MachineType::Uint8(), MachineType::Int16(), |
| MachineType::Uint16(), MachineType::Int32(), MachineType::Uint32(), |
| MachineType::Int64(), MachineType::Uint64(), MachineType::Float32(), |
| MachineType::Float64()}; |
| |
| for (size_t m = 0; m < arraysize(machineTypes); m++) { |
| WasmRunner<int32_t, uint32_t> r(execution_mode); |
| byte* memory = r.builder().AddMemoryElems<byte>(32); |
| r.builder().RandomizeMemory(1119 + static_cast<int>(m)); |
| |
| BUILD(r, WASM_STORE_MEM_OFFSET(machineTypes[m], 8, WASM_GET_LOCAL(0), |
| WASM_LOAD_MEM(machineTypes[m], WASM_ZERO)), |
| WASM_ZERO); |
| |
| byte memsize = WasmOpcodes::MemSize(machineTypes[m]); |
| uint32_t boundary = 24 - memsize; |
| CHECK_EQ(0, r.Call(boundary)); // in bounds. |
| CHECK_EQ(0, memcmp(&memory[0], &memory[8 + boundary], memsize)); |
| |
| for (uint32_t offset = boundary + 1; offset < boundary + 19; offset++) { |
| CHECK_TRAP32(r.Call(offset)); // out of bounds. |
| } |
| } |
| } |
| |
| WASM_EXEC_TEST(Store_i64_narrowed) { |
| constexpr byte kOpcodes[] = {kExprI64StoreMem8, kExprI64StoreMem16, |
| kExprI64StoreMem32, kExprI64StoreMem}; |
| int stored_size_in_bytes = 0; |
| for (auto opcode : kOpcodes) { |
| stored_size_in_bytes = std::max(1, stored_size_in_bytes * 2); |
| constexpr int kBytes = 24; |
| uint8_t expected_memory[kBytes] = {0}; |
| WasmRunner<int32_t, int32_t, int64_t> r(execution_mode); |
| uint8_t* memory = r.builder().AddMemoryElems<uint8_t>(kBytes); |
| constexpr uint64_t kPattern = 0x0123456789abcdef; |
| |
| BUILD(r, WASM_GET_LOCAL(0), // index |
| WASM_GET_LOCAL(1), // value |
| opcode, ZERO_ALIGNMENT, ZERO_OFFSET, // store |
| WASM_ZERO); // return value |
| |
| for (int i = 0; i <= kBytes - stored_size_in_bytes; ++i) { |
| uint64_t pattern = base::bits::RotateLeft64(kPattern, i % 64); |
| r.Call(i, pattern); |
| for (int b = 0; b < stored_size_in_bytes; ++b) { |
| expected_memory[i + b] = static_cast<uint8_t>(pattern >> (b * 8)); |
| } |
| for (int w = 0; w < kBytes; ++w) { |
| CHECK_EQ(expected_memory[w], memory[w]); |
| } |
| } |
| } |
| } |
| |
| WASM_EXEC_TEST(UnalignedInt64Load) { |
| WasmRunner<uint64_t> r(execution_mode); |
| r.builder().AddMemoryElems<int64_t>(8); |
| BUILD(r, WASM_LOAD_MEM_ALIGNMENT(MachineType::Int64(), WASM_ONE, 3)); |
| r.Call(); |
| } |
| |
| WASM_EXEC_TEST(UnalignedInt64Store) { |
| WasmRunner<int32_t> r(execution_mode); |
| r.builder().AddMemoryElems<uint64_t>(8); |
| BUILD(r, WASM_SEQ(WASM_STORE_MEM_ALIGNMENT(MachineType::Int64(), WASM_ONE, 3, |
| WASM_I64V_1(1)), |
| WASM_I32V_1(12))); |
| r.Call(); |
| } |
| |
| #define ADD_CODE(vec, ...) \ |
| do { \ |
| byte __buf[] = {__VA_ARGS__}; \ |
| for (size_t i = 0; i < sizeof(__buf); i++) vec.push_back(__buf[i]); \ |
| } while (false) |
| |
| static void CompileCallIndirectMany(WasmExecutionMode mode, ValueType param) { |
| // Make sure we don't run out of registers when compiling indirect calls |
| // with many many parameters. |
| TestSignatures sigs; |
| for (byte num_params = 0; num_params < 40; num_params++) { |
| WasmRunner<void> r(mode); |
| FunctionSig* sig = sigs.many(r.zone(), kWasmStmt, param, num_params); |
| |
| r.builder().AddSignature(sig); |
| r.builder().AddSignature(sig); |
| r.builder().AddIndirectFunctionTable(nullptr, 0); |
| |
| WasmFunctionCompiler& t = r.NewFunction(sig); |
| |
| std::vector<byte> code; |
| for (byte p = 0; p < num_params; p++) { |
| ADD_CODE(code, kExprGetLocal, p); |
| } |
| ADD_CODE(code, kExprI32Const, 0); |
| ADD_CODE(code, kExprCallIndirect, 1, TABLE_ZERO); |
| |
| t.Build(&code[0], &code[0] + code.size()); |
| } |
| } |
| |
| WASM_EXEC_TEST(Compile_Wasm_CallIndirect_Many_i64) { |
| CompileCallIndirectMany(execution_mode, kWasmI64); |
| } |
| |
| static void Run_WasmMixedCall_N(WasmExecutionMode execution_mode, int start) { |
| const int kExpected = 6333; |
| const int kElemSize = 8; |
| TestSignatures sigs; |
| |
| static MachineType mixed[] = { |
| MachineType::Int32(), MachineType::Float32(), MachineType::Int64(), |
| MachineType::Float64(), MachineType::Float32(), MachineType::Int64(), |
| MachineType::Int32(), MachineType::Float64(), MachineType::Float32(), |
| MachineType::Float64(), MachineType::Int32(), MachineType::Int64(), |
| MachineType::Int32(), MachineType::Int32()}; |
| |
| int num_params = static_cast<int>(arraysize(mixed)) - start; |
| for (int which = 0; which < num_params; which++) { |
| v8::internal::AccountingAllocator allocator; |
| Zone zone(&allocator, ZONE_NAME); |
| WasmRunner<int32_t> r(execution_mode); |
| r.builder().AddMemory(1024); |
| MachineType* memtypes = &mixed[start]; |
| MachineType result = memtypes[which]; |
| |
| // ========================================================================= |
| // Build the selector function. |
| // ========================================================================= |
| FunctionSig::Builder b(&zone, 1, num_params); |
| b.AddReturn(WasmOpcodes::ValueTypeFor(result)); |
| for (int i = 0; i < num_params; i++) { |
| b.AddParam(WasmOpcodes::ValueTypeFor(memtypes[i])); |
| } |
| WasmFunctionCompiler& t = r.NewFunction(b.Build()); |
| BUILD(t, WASM_GET_LOCAL(which)); |
| |
| // ========================================================================= |
| // Build the calling function. |
| // ========================================================================= |
| std::vector<byte> code; |
| |
| // Load the arguments. |
| for (int i = 0; i < num_params; i++) { |
| int offset = (i + 1) * kElemSize; |
| ADD_CODE(code, WASM_LOAD_MEM(memtypes[i], WASM_I32V_2(offset))); |
| } |
| |
| // Call the selector function. |
| ADD_CODE(code, WASM_CALL_FUNCTION0(t.function_index())); |
| |
| // Store the result in a local. |
| byte local_index = r.AllocateLocal(WasmOpcodes::ValueTypeFor(result)); |
| ADD_CODE(code, kExprSetLocal, local_index); |
| |
| // Store the result in memory. |
| ADD_CODE(code, |
| WASM_STORE_MEM(result, WASM_ZERO, WASM_GET_LOCAL(local_index))); |
| |
| // Return the expected value. |
| ADD_CODE(code, WASM_I32V_2(kExpected)); |
| |
| r.Build(&code[0], &code[0] + code.size()); |
| |
| // Run the code. |
| for (int t = 0; t < 10; t++) { |
| r.builder().RandomizeMemory(); |
| CHECK_EQ(kExpected, r.Call()); |
| |
| int size = WasmOpcodes::MemSize(result); |
| for (int i = 0; i < size; i++) { |
| int base = (which + 1) * kElemSize; |
| byte expected = r.builder().raw_mem_at<byte>(base + i); |
| byte result = r.builder().raw_mem_at<byte>(i); |
| CHECK_EQ(expected, result); |
| } |
| } |
| } |
| } |
| |
| WASM_EXEC_TEST(MixedCall_i64_0) { Run_WasmMixedCall_N(execution_mode, 0); } |
| WASM_EXEC_TEST(MixedCall_i64_1) { Run_WasmMixedCall_N(execution_mode, 1); } |
| WASM_EXEC_TEST(MixedCall_i64_2) { Run_WasmMixedCall_N(execution_mode, 2); } |
| WASM_EXEC_TEST(MixedCall_i64_3) { Run_WasmMixedCall_N(execution_mode, 3); } |
| |
| WASM_EXEC_TEST(Regress5874) { |
| REQUIRE(I32ConvertI64); |
| REQUIRE(I64LoadStore); |
| REQUIRE(I64Const); |
| WasmRunner<int32_t> r(execution_mode); |
| r.builder().AddMemoryElems<int64_t>(8); |
| |
| BUILD(r, kExprI64Const, 0x00, // -- |
| kExprI32ConvertI64, // -- |
| kExprI64Const, 0x00, // -- |
| kExprI64StoreMem, 0x03, 0x00, // -- |
| kExprI32Const, 0x00); // -- |
| |
| r.Call(); |
| } |
| |
| WASM_EXEC_TEST(Regression_6858) { |
| REQUIRE(I64DivS); |
| // WasmRunner with 5 params and returns, which is the maximum. |
| WasmRunner<int64_t, int64_t, int64_t, int64_t, int64_t> r(execution_mode); |
| BUILD(r, WASM_I64_DIVS(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))); |
| int64_t dividend = 15; |
| int64_t divisor = 0; |
| int64_t filler = 34; |
| CHECK_TRAP64(r.Call(dividend, divisor, filler, filler)); |
| } |
| |
| #undef WASM_64 |
| #undef MIPS |
| #undef REQUIRE |
| #undef ADD_CODE |
| |
| // clang-format gets confused about these closing parentheses (wants to change |
| // the first comment to "// namespace v8". Disable it. |
| // clang-format off |
| } // namespace test_run_wasm_64 |
| } // namespace wasm |
| } // namespace internal |
| } // namespace v8 |
| // clang-format on |