2017-08-02 21:40:45 +00:00
|
|
|
// Copyright 2017 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.
|
|
|
|
|
2017-09-13 10:56:20 +00:00
|
|
|
#include "src/objects-inl.h"
|
2017-08-02 21:40:45 +00:00
|
|
|
#include "test/cctest/cctest.h"
|
|
|
|
#include "test/cctest/compiler/value-helper.h"
|
|
|
|
#include "test/cctest/wasm/wasm-run-utils.h"
|
|
|
|
#include "test/common/wasm/wasm-macro-gen.h"
|
|
|
|
|
2017-09-01 12:57:34 +00:00
|
|
|
namespace v8 {
|
|
|
|
namespace internal {
|
|
|
|
namespace wasm {
|
|
|
|
|
2017-08-02 21:40:45 +00:00
|
|
|
typedef uint32_t (*Uint32BinOp)(uint32_t, uint32_t);
|
|
|
|
typedef uint16_t (*Uint16BinOp)(uint16_t, uint16_t);
|
|
|
|
typedef uint8_t (*Uint8BinOp)(uint8_t, uint8_t);
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
T Add(T a, T b) {
|
|
|
|
return a + b;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
T Sub(T a, T b) {
|
|
|
|
return a - b;
|
|
|
|
}
|
|
|
|
|
[wasm] Implement atomic logical BinOps
- Implemented ops: I32AtomicAnd, I32AtomicAnd8U, I32AtomicAnd16U, I32AtomicOr,
I32AtomicOr8U, I32AtomicOr16U, I32AtomicXor, I32AtomicXor8U, I32AtomicXor16U
- Refactor wasm-compiler AtomicOp to use macros
- Tests
Bug:V8:6532
R=binji@chromium.org, bbudge@chromium.org, bradnelson@chromium.org
Change-Id: I7e4dc8ad8cf3e211c3aef721a02778f2a4621322
Reviewed-on: https://chromium-review.googlesource.com/600539
Reviewed-by: Bill Budge <bbudge@chromium.org>
Commit-Queue: Deepti Gandluri <gdeepti@chromium.org>
Cr-Commit-Position: refs/heads/master@{#47172}
2017-08-03 19:54:41 +00:00
|
|
|
template <typename T>
|
|
|
|
T And(T a, T b) {
|
|
|
|
return a & b;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
T Or(T a, T b) {
|
|
|
|
return a | b;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
T Xor(T a, T b) {
|
|
|
|
return a ^ b;
|
|
|
|
}
|
|
|
|
|
2017-08-25 21:30:35 +00:00
|
|
|
template <typename T>
|
|
|
|
T Exchange(T a, T b) {
|
|
|
|
return b;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
T CompareExchange(T initial, T a, T b) {
|
|
|
|
if (initial == a) return b;
|
|
|
|
return a;
|
|
|
|
}
|
|
|
|
|
2017-08-02 21:40:45 +00:00
|
|
|
void RunU32BinOp(WasmOpcode wasm_op, Uint32BinOp expected_op) {
|
|
|
|
EXPERIMENTAL_FLAG_SCOPE(threads);
|
|
|
|
WasmRunner<uint32_t, uint32_t> r(kExecuteCompiled);
|
2017-08-19 16:34:11 +00:00
|
|
|
uint32_t* memory = r.builder().AddMemoryElems<uint32_t>(8);
|
2017-09-14 06:14:48 +00:00
|
|
|
r.builder().SetHasSharedMemory();
|
2017-08-02 21:40:45 +00:00
|
|
|
|
2017-09-23 18:59:12 +00:00
|
|
|
BUILD(r, WASM_ATOMICS_BINOP(wasm_op, WASM_I32V_1(0), WASM_GET_LOCAL(0),
|
|
|
|
MachineRepresentation::kWord32));
|
2017-08-02 21:40:45 +00:00
|
|
|
|
|
|
|
FOR_UINT32_INPUTS(i) {
|
|
|
|
uint32_t initial = *i;
|
|
|
|
FOR_UINT32_INPUTS(j) {
|
2017-08-19 16:34:11 +00:00
|
|
|
r.builder().WriteMemory(&memory[0], initial);
|
2017-08-02 21:40:45 +00:00
|
|
|
CHECK_EQ(initial, r.Call(*j));
|
|
|
|
uint32_t expected = expected_op(*i, *j);
|
2017-08-19 16:34:11 +00:00
|
|
|
CHECK_EQ(expected, r.builder().ReadMemory(&memory[0]));
|
2017-08-02 21:40:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-09-20 09:06:09 +00:00
|
|
|
TEST(I32AtomicAdd) { RunU32BinOp(kExprI32AtomicAdd, Add); }
|
|
|
|
TEST(I32AtomicSub) { RunU32BinOp(kExprI32AtomicSub, Sub); }
|
|
|
|
TEST(I32AtomicAnd) { RunU32BinOp(kExprI32AtomicAnd, And); }
|
|
|
|
TEST(I32AtomicOr) { RunU32BinOp(kExprI32AtomicOr, Or); }
|
|
|
|
TEST(I32AtomicXor) { RunU32BinOp(kExprI32AtomicXor, Xor); }
|
|
|
|
TEST(I32AtomicExchange) { RunU32BinOp(kExprI32AtomicExchange, Exchange); }
|
2017-08-02 21:40:45 +00:00
|
|
|
|
|
|
|
void RunU16BinOp(WasmOpcode wasm_op, Uint16BinOp expected_op) {
|
|
|
|
EXPERIMENTAL_FLAG_SCOPE(threads);
|
|
|
|
WasmRunner<uint32_t, uint32_t> r(kExecuteCompiled);
|
2017-09-14 06:14:48 +00:00
|
|
|
r.builder().SetHasSharedMemory();
|
2017-08-19 16:34:11 +00:00
|
|
|
uint16_t* memory = r.builder().AddMemoryElems<uint16_t>(8);
|
2017-08-02 21:40:45 +00:00
|
|
|
|
2017-09-23 18:59:12 +00:00
|
|
|
BUILD(r, WASM_ATOMICS_BINOP(wasm_op, WASM_I32V_1(0), WASM_GET_LOCAL(0),
|
|
|
|
MachineRepresentation::kWord16));
|
2017-08-02 21:40:45 +00:00
|
|
|
|
|
|
|
FOR_UINT16_INPUTS(i) {
|
|
|
|
uint16_t initial = *i;
|
|
|
|
FOR_UINT16_INPUTS(j) {
|
2017-08-19 16:34:11 +00:00
|
|
|
r.builder().WriteMemory(&memory[0], initial);
|
2017-08-02 21:40:45 +00:00
|
|
|
CHECK_EQ(initial, r.Call(*j));
|
|
|
|
uint16_t expected = expected_op(*i, *j);
|
2017-08-19 16:34:11 +00:00
|
|
|
CHECK_EQ(expected, r.builder().ReadMemory(&memory[0]));
|
2017-08-02 21:40:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-09-20 09:06:09 +00:00
|
|
|
TEST(I32AtomicAdd16U) { RunU16BinOp(kExprI32AtomicAdd16U, Add); }
|
|
|
|
TEST(I32AtomicSub16U) { RunU16BinOp(kExprI32AtomicSub16U, Sub); }
|
|
|
|
TEST(I32AtomicAnd16U) { RunU16BinOp(kExprI32AtomicAnd16U, And); }
|
|
|
|
TEST(I32AtomicOr16U) { RunU16BinOp(kExprI32AtomicOr16U, Or); }
|
|
|
|
TEST(I32AtomicXor16U) { RunU16BinOp(kExprI32AtomicXor16U, Xor); }
|
|
|
|
TEST(I32AtomicExchange16U) { RunU16BinOp(kExprI32AtomicExchange16U, Exchange); }
|
2017-08-02 21:40:45 +00:00
|
|
|
|
|
|
|
void RunU8BinOp(WasmOpcode wasm_op, Uint8BinOp expected_op) {
|
|
|
|
EXPERIMENTAL_FLAG_SCOPE(threads);
|
|
|
|
WasmRunner<uint32_t, uint32_t> r(kExecuteCompiled);
|
2017-09-14 06:14:48 +00:00
|
|
|
r.builder().SetHasSharedMemory();
|
2017-08-19 16:34:11 +00:00
|
|
|
uint8_t* memory = r.builder().AddMemoryElems<uint8_t>(8);
|
2017-08-02 21:40:45 +00:00
|
|
|
|
2017-09-23 18:59:12 +00:00
|
|
|
BUILD(r, WASM_ATOMICS_BINOP(wasm_op, WASM_I32V_1(0), WASM_GET_LOCAL(0),
|
|
|
|
MachineRepresentation::kWord8));
|
2017-08-02 21:40:45 +00:00
|
|
|
|
|
|
|
FOR_UINT8_INPUTS(i) {
|
|
|
|
uint8_t initial = *i;
|
|
|
|
FOR_UINT8_INPUTS(j) {
|
2017-08-19 16:34:11 +00:00
|
|
|
r.builder().WriteMemory(&memory[0], initial);
|
2017-08-02 21:40:45 +00:00
|
|
|
CHECK_EQ(initial, r.Call(*j));
|
|
|
|
uint8_t expected = expected_op(*i, *j);
|
2017-08-19 16:34:11 +00:00
|
|
|
CHECK_EQ(expected, r.builder().ReadMemory(&memory[0]));
|
2017-08-02 21:40:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-09-20 09:06:09 +00:00
|
|
|
TEST(I32AtomicAdd8U) { RunU8BinOp(kExprI32AtomicAdd8U, Add); }
|
|
|
|
TEST(I32AtomicSub8U) { RunU8BinOp(kExprI32AtomicSub8U, Sub); }
|
|
|
|
TEST(I32AtomicAnd8U) { RunU8BinOp(kExprI32AtomicAnd8U, And); }
|
|
|
|
TEST(I32AtomicOr8U) { RunU8BinOp(kExprI32AtomicOr8U, Or); }
|
|
|
|
TEST(I32AtomicXor8U) { RunU8BinOp(kExprI32AtomicXor8U, Xor); }
|
|
|
|
TEST(I32AtomicExchange8U) { RunU8BinOp(kExprI32AtomicExchange8U, Exchange); }
|
2017-08-25 21:30:35 +00:00
|
|
|
|
2017-09-20 09:06:09 +00:00
|
|
|
TEST(I32AtomicCompareExchange) {
|
2017-08-25 21:30:35 +00:00
|
|
|
EXPERIMENTAL_FLAG_SCOPE(threads);
|
|
|
|
WasmRunner<uint32_t, uint32_t, uint32_t> r(kExecuteCompiled);
|
2017-09-14 06:14:48 +00:00
|
|
|
r.builder().SetHasSharedMemory();
|
2017-08-25 21:30:35 +00:00
|
|
|
uint32_t* memory = r.builder().AddMemoryElems<uint32_t>(8);
|
2017-09-23 18:59:12 +00:00
|
|
|
BUILD(r, WASM_ATOMICS_TERNARY_OP(
|
|
|
|
kExprI32AtomicCompareExchange, WASM_I32V_1(0), WASM_GET_LOCAL(0),
|
|
|
|
WASM_GET_LOCAL(1), MachineRepresentation::kWord32));
|
2017-08-25 21:30:35 +00:00
|
|
|
|
|
|
|
FOR_UINT32_INPUTS(i) {
|
|
|
|
uint32_t initial = *i;
|
|
|
|
FOR_UINT32_INPUTS(j) {
|
|
|
|
r.builder().WriteMemory(&memory[0], initial);
|
|
|
|
CHECK_EQ(initial, r.Call(*i, *j));
|
|
|
|
uint32_t expected = CompareExchange(initial, *i, *j);
|
|
|
|
CHECK_EQ(expected, r.builder().ReadMemory(&memory[0]));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-09-20 09:06:09 +00:00
|
|
|
TEST(I32AtomicCompareExchange16U) {
|
2017-08-25 21:30:35 +00:00
|
|
|
EXPERIMENTAL_FLAG_SCOPE(threads);
|
|
|
|
WasmRunner<uint32_t, uint32_t, uint32_t> r(kExecuteCompiled);
|
2017-09-14 06:14:48 +00:00
|
|
|
r.builder().SetHasSharedMemory();
|
2017-08-25 21:30:35 +00:00
|
|
|
uint16_t* memory = r.builder().AddMemoryElems<uint16_t>(8);
|
|
|
|
BUILD(r, WASM_ATOMICS_TERNARY_OP(kExprI32AtomicCompareExchange16U,
|
|
|
|
WASM_I32V_1(0), WASM_GET_LOCAL(0),
|
2017-09-23 18:59:12 +00:00
|
|
|
WASM_GET_LOCAL(1),
|
|
|
|
MachineRepresentation::kWord16));
|
2017-08-25 21:30:35 +00:00
|
|
|
|
|
|
|
FOR_UINT16_INPUTS(i) {
|
|
|
|
uint16_t initial = *i;
|
|
|
|
FOR_UINT16_INPUTS(j) {
|
|
|
|
r.builder().WriteMemory(&memory[0], initial);
|
|
|
|
CHECK_EQ(initial, r.Call(*i, *j));
|
|
|
|
uint16_t expected = CompareExchange(initial, *i, *j);
|
|
|
|
CHECK_EQ(expected, r.builder().ReadMemory(&memory[0]));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-09-20 09:06:09 +00:00
|
|
|
TEST(I32AtomicCompareExchange8U) {
|
2017-08-25 21:30:35 +00:00
|
|
|
EXPERIMENTAL_FLAG_SCOPE(threads);
|
|
|
|
WasmRunner<uint32_t, uint32_t, uint32_t> r(kExecuteCompiled);
|
2017-09-14 06:14:48 +00:00
|
|
|
r.builder().SetHasSharedMemory();
|
2017-08-25 21:30:35 +00:00
|
|
|
uint8_t* memory = r.builder().AddMemoryElems<uint8_t>(8);
|
|
|
|
BUILD(r,
|
|
|
|
WASM_ATOMICS_TERNARY_OP(kExprI32AtomicCompareExchange8U, WASM_I32V_1(0),
|
2017-09-23 18:59:12 +00:00
|
|
|
WASM_GET_LOCAL(0), WASM_GET_LOCAL(1),
|
|
|
|
MachineRepresentation::kWord8));
|
2017-08-25 21:30:35 +00:00
|
|
|
|
|
|
|
FOR_UINT8_INPUTS(i) {
|
|
|
|
uint8_t initial = *i;
|
|
|
|
FOR_UINT8_INPUTS(j) {
|
|
|
|
r.builder().WriteMemory(&memory[0], initial);
|
|
|
|
CHECK_EQ(initial, r.Call(*i, *j));
|
|
|
|
uint8_t expected = CompareExchange(initial, *i, *j);
|
|
|
|
CHECK_EQ(expected, r.builder().ReadMemory(&memory[0]));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-09-01 12:57:34 +00:00
|
|
|
|
2017-10-02 05:05:45 +00:00
|
|
|
TEST(I32AtomicLoad) {
|
|
|
|
EXPERIMENTAL_FLAG_SCOPE(threads);
|
|
|
|
WasmRunner<uint32_t> r(kExecuteCompiled);
|
|
|
|
r.builder().SetHasSharedMemory();
|
|
|
|
uint32_t* memory = r.builder().AddMemoryElems<uint32_t>(8);
|
|
|
|
BUILD(r, WASM_ATOMICS_LOAD_OP(kExprI32AtomicLoad, WASM_ZERO,
|
|
|
|
MachineRepresentation::kWord32));
|
|
|
|
|
|
|
|
FOR_UINT32_INPUTS(i) {
|
|
|
|
uint32_t expected = *i;
|
|
|
|
r.builder().WriteMemory(&memory[0], expected);
|
|
|
|
CHECK_EQ(expected, r.Call());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(I32AtomicLoad16U) {
|
|
|
|
EXPERIMENTAL_FLAG_SCOPE(threads);
|
|
|
|
WasmRunner<uint32_t> r(kExecuteCompiled);
|
|
|
|
r.builder().SetHasSharedMemory();
|
|
|
|
uint16_t* memory = r.builder().AddMemoryElems<uint16_t>(8);
|
|
|
|
BUILD(r, WASM_ATOMICS_LOAD_OP(kExprI32AtomicLoad16U, WASM_ZERO,
|
|
|
|
MachineRepresentation::kWord16));
|
|
|
|
|
|
|
|
FOR_UINT16_INPUTS(i) {
|
|
|
|
uint16_t expected = *i;
|
|
|
|
r.builder().WriteMemory(&memory[0], expected);
|
|
|
|
CHECK_EQ(expected, r.Call());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(I32AtomicLoad8U) {
|
|
|
|
EXPERIMENTAL_FLAG_SCOPE(threads);
|
|
|
|
WasmRunner<uint32_t> r(kExecuteCompiled);
|
|
|
|
r.builder().SetHasSharedMemory();
|
|
|
|
uint8_t* memory = r.builder().AddMemoryElems<uint8_t>(8);
|
|
|
|
BUILD(r, WASM_ATOMICS_LOAD_OP(kExprI32AtomicLoad8U, WASM_ZERO,
|
|
|
|
MachineRepresentation::kWord8));
|
|
|
|
|
|
|
|
FOR_UINT8_INPUTS(i) {
|
|
|
|
uint8_t expected = *i;
|
|
|
|
r.builder().WriteMemory(&memory[0], expected);
|
|
|
|
CHECK_EQ(expected, r.Call());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(I32AtomicStoreLoad) {
|
|
|
|
EXPERIMENTAL_FLAG_SCOPE(threads);
|
|
|
|
WasmRunner<uint32_t, uint32_t> r(kExecuteCompiled);
|
|
|
|
r.builder().SetHasSharedMemory();
|
|
|
|
uint32_t* memory = r.builder().AddMemoryElems<uint32_t>(8);
|
|
|
|
|
|
|
|
BUILD(r,
|
|
|
|
WASM_ATOMICS_STORE_OP(kExprI32AtomicStore, WASM_ZERO, WASM_GET_LOCAL(0),
|
|
|
|
MachineRepresentation::kWord32),
|
|
|
|
WASM_ATOMICS_LOAD_OP(kExprI32AtomicLoad, WASM_ZERO,
|
|
|
|
MachineRepresentation::kWord32));
|
|
|
|
|
|
|
|
FOR_UINT32_INPUTS(i) {
|
|
|
|
uint32_t expected = *i;
|
|
|
|
CHECK_EQ(expected, r.Call(*i));
|
|
|
|
CHECK_EQ(expected, r.builder().ReadMemory(&memory[0]));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(I32AtomicStoreLoad16U) {
|
|
|
|
EXPERIMENTAL_FLAG_SCOPE(threads);
|
|
|
|
WasmRunner<uint32_t, uint32_t> r(kExecuteCompiled);
|
|
|
|
r.builder().SetHasSharedMemory();
|
|
|
|
uint16_t* memory = r.builder().AddMemoryElems<uint16_t>(8);
|
|
|
|
|
|
|
|
BUILD(
|
|
|
|
r,
|
|
|
|
WASM_ATOMICS_STORE_OP(kExprI32AtomicStore16U, WASM_ZERO,
|
|
|
|
WASM_GET_LOCAL(0), MachineRepresentation::kWord16),
|
|
|
|
WASM_ATOMICS_LOAD_OP(kExprI32AtomicLoad16U, WASM_ZERO,
|
|
|
|
MachineRepresentation::kWord16));
|
|
|
|
|
|
|
|
FOR_UINT16_INPUTS(i) {
|
|
|
|
uint16_t expected = *i;
|
|
|
|
CHECK_EQ(expected, r.Call(*i));
|
|
|
|
CHECK_EQ(expected, r.builder().ReadMemory(&memory[0]));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(I32AtomicStoreLoad8U) {
|
|
|
|
EXPERIMENTAL_FLAG_SCOPE(threads);
|
|
|
|
WasmRunner<uint32_t, uint32_t> r(kExecuteCompiled);
|
|
|
|
r.builder().SetHasSharedMemory();
|
|
|
|
uint8_t* memory = r.builder().AddMemoryElems<uint8_t>(8);
|
|
|
|
|
|
|
|
BUILD(r,
|
|
|
|
WASM_ATOMICS_STORE_OP(kExprI32AtomicStore8U, WASM_ZERO,
|
|
|
|
WASM_GET_LOCAL(0), MachineRepresentation::kWord8),
|
|
|
|
WASM_ATOMICS_LOAD_OP(kExprI32AtomicLoad8U, WASM_ZERO,
|
|
|
|
MachineRepresentation::kWord8));
|
|
|
|
|
|
|
|
FOR_UINT8_INPUTS(i) {
|
|
|
|
uint8_t expected = *i;
|
|
|
|
CHECK_EQ(expected, r.Call(*i));
|
|
|
|
CHECK_EQ(*i, r.builder().ReadMemory(&memory[0]));
|
|
|
|
}
|
|
|
|
}
|
2017-09-08 13:59:05 +00:00
|
|
|
|
2017-09-01 12:57:34 +00:00
|
|
|
} // namespace wasm
|
|
|
|
} // namespace internal
|
|
|
|
} // namespace v8
|