Commit ff8bbe24 authored by aseemgarg's avatar aseemgarg Committed by Commit bot

[wasm] implement simd lowering for replaceLane, load, store and test for phi

BUG=v8:4124
TEST:test-run-wasm-simd-lowering
R=bradnelson@chromium.org,titzer@chromium.org,mtrofin@chromium.org

Review-Url: https://codereview.chromium.org/2498283002
Cr-Commit-Position: refs/heads/master@{#41443}
parent 2c1fb7a8
......@@ -58,6 +58,9 @@ void SimdScalarLowering::LowerGraph() {
// that they are processed after all other nodes.
PreparePhiReplacement(input);
stack_.push_front({input, 0});
} else if (input->opcode() == IrOpcode::kEffectPhi ||
input->opcode() == IrOpcode::kLoop) {
stack_.push_front({input, 0});
} else {
stack_.push_back({input, 0});
}
......@@ -70,12 +73,14 @@ void SimdScalarLowering::LowerGraph() {
#define FOREACH_INT32X4_OPCODE(V) \
V(Int32x4Add) \
V(Int32x4ExtractLane) \
V(CreateInt32x4)
V(CreateInt32x4) \
V(Int32x4ReplaceLane)
#define FOREACH_FLOAT32X4_OPCODE(V) \
V(Float32x4Add) \
V(Float32x4ExtractLane) \
V(CreateFloat32x4)
V(CreateFloat32x4) \
V(Float32x4ReplaceLane)
void SimdScalarLowering::SetLoweredType(Node* node, Node* output) {
switch (node->opcode()) {
......@@ -102,7 +107,7 @@ static int GetParameterIndexAfterLowering(
// In function calls, the simd128 types are passed as 4 Int32 types. The
// parameters are typecast to the types as needed for various operations.
int result = old_index;
for (int i = 0; i < old_index; i++) {
for (int i = 0; i < old_index; ++i) {
if (signature->GetParam(i) == MachineRepresentation::kSimd128) {
result += 3;
}
......@@ -123,7 +128,7 @@ int SimdScalarLowering::GetParameterCountAfterLowering() {
static int GetReturnCountAfterLowering(
Signature<MachineRepresentation>* signature) {
int result = static_cast<int>(signature->return_count());
for (int i = 0; i < static_cast<int>(signature->return_count()); i++) {
for (int i = 0; i < static_cast<int>(signature->return_count()); ++i) {
if (signature->GetReturn(i) == MachineRepresentation::kSimd128) {
result += 3;
}
......@@ -131,6 +136,100 @@ static int GetReturnCountAfterLowering(
return result;
}
void SimdScalarLowering::GetIndexNodes(Node* index, Node** new_indices) {
new_indices[0] = index;
for (size_t i = 1; i < kMaxLanes; ++i) {
new_indices[i] = graph()->NewNode(machine()->Int32Add(), index,
graph()->NewNode(common()->Int32Constant(
static_cast<int>(i) * kLaneWidth)));
}
}
void SimdScalarLowering::LowerLoadOp(MachineRepresentation rep, Node* node,
const Operator* load_op) {
if (rep == MachineRepresentation::kSimd128) {
Node* base = node->InputAt(0);
Node* index = node->InputAt(1);
Node* indices[kMaxLanes];
GetIndexNodes(index, indices);
Node* rep_nodes[kMaxLanes];
rep_nodes[0] = node;
NodeProperties::ChangeOp(rep_nodes[0], load_op);
if (node->InputCount() > 2) {
DCHECK(node->InputCount() > 3);
Node* effect_input = node->InputAt(2);
Node* control_input = node->InputAt(3);
rep_nodes[3] = graph()->NewNode(load_op, base, indices[3], effect_input,
control_input);
rep_nodes[2] = graph()->NewNode(load_op, base, indices[2], rep_nodes[3],
control_input);
rep_nodes[1] = graph()->NewNode(load_op, base, indices[1], rep_nodes[2],
control_input);
rep_nodes[0]->ReplaceInput(2, rep_nodes[1]);
} else {
for (size_t i = 1; i < kMaxLanes; ++i) {
rep_nodes[i] = graph()->NewNode(load_op, base, indices[i]);
}
}
ReplaceNode(node, rep_nodes);
} else {
DefaultLowering(node);
}
}
void SimdScalarLowering::LowerStoreOp(MachineRepresentation rep, Node* node,
const Operator* store_op,
SimdType rep_type) {
if (rep == MachineRepresentation::kSimd128) {
Node* base = node->InputAt(0);
Node* index = node->InputAt(1);
Node* indices[kMaxLanes];
GetIndexNodes(index, indices);
DCHECK(node->InputCount() > 2);
Node* value = node->InputAt(2);
DCHECK(HasReplacement(1, value));
Node* rep_nodes[kMaxLanes];
rep_nodes[0] = node;
Node** rep_inputs = GetReplacementsWithType(value, rep_type);
rep_nodes[0]->ReplaceInput(2, rep_inputs[0]);
NodeProperties::ChangeOp(node, store_op);
if (node->InputCount() > 3) {
DCHECK(node->InputCount() > 4);
Node* effect_input = node->InputAt(3);
Node* control_input = node->InputAt(4);
rep_nodes[3] = graph()->NewNode(store_op, base, indices[3], rep_inputs[3],
effect_input, control_input);
rep_nodes[2] = graph()->NewNode(store_op, base, indices[2], rep_inputs[2],
rep_nodes[3], control_input);
rep_nodes[1] = graph()->NewNode(store_op, base, indices[1], rep_inputs[1],
rep_nodes[2], control_input);
rep_nodes[0]->ReplaceInput(3, rep_nodes[1]);
} else {
for (size_t i = 1; i < kMaxLanes; ++i) {
rep_nodes[i] =
graph()->NewNode(store_op, base, indices[i], rep_inputs[i]);
}
}
ReplaceNode(node, rep_nodes);
} else {
DefaultLowering(node);
}
}
void SimdScalarLowering::LowerBinaryOp(Node* node, SimdType rep_type,
const Operator* op) {
DCHECK(node->InputCount() == 2);
Node** rep_left = GetReplacementsWithType(node->InputAt(0), rep_type);
Node** rep_right = GetReplacementsWithType(node->InputAt(1), rep_type);
Node* rep_node[kMaxLanes];
for (int i = 0; i < kMaxLanes; ++i) {
rep_node[i] = graph()->NewNode(op, rep_left[i], rep_right[i]);
}
ReplaceNode(node, rep_node);
}
void SimdScalarLowering::LowerNode(Node* node) {
SimdType rep_type = ReplacementType(node);
switch (node->opcode()) {
......@@ -159,13 +258,13 @@ void SimdScalarLowering::LowerNode(Node* node) {
NodeProperties::ChangeOp(node, common()->Parameter(new_index));
Node* new_node[kMaxLanes];
for (int i = 0; i < kMaxLanes; i++) {
for (int i = 0; i < kMaxLanes; ++i) {
new_node[i] = nullptr;
}
new_node[0] = node;
if (signature()->GetParam(old_index) ==
MachineRepresentation::kSimd128) {
for (int i = 1; i < kMaxLanes; i++) {
for (int i = 1; i < kMaxLanes; ++i) {
new_node[i] = graph()->NewNode(common()->Parameter(new_index + i),
graph()->start());
}
......@@ -175,6 +274,57 @@ void SimdScalarLowering::LowerNode(Node* node) {
}
break;
}
case IrOpcode::kLoad: {
MachineRepresentation rep =
LoadRepresentationOf(node->op()).representation();
const Operator* load_op;
if (rep_type == SimdType::kInt32) {
load_op = machine()->Load(MachineType::Int32());
} else if (rep_type == SimdType::kFloat32) {
load_op = machine()->Load(MachineType::Float32());
}
LowerLoadOp(rep, node, load_op);
break;
}
case IrOpcode::kUnalignedLoad: {
MachineRepresentation rep =
UnalignedLoadRepresentationOf(node->op()).representation();
const Operator* load_op;
if (rep_type == SimdType::kInt32) {
load_op = machine()->UnalignedLoad(MachineType::Int32());
} else if (rep_type == SimdType::kFloat32) {
load_op = machine()->UnalignedLoad(MachineType::Float32());
}
LowerLoadOp(rep, node, load_op);
break;
}
case IrOpcode::kStore: {
MachineRepresentation rep =
StoreRepresentationOf(node->op()).representation();
WriteBarrierKind write_barrier_kind =
StoreRepresentationOf(node->op()).write_barrier_kind();
const Operator* store_op;
if (rep_type == SimdType::kInt32) {
store_op = machine()->Store(StoreRepresentation(
MachineRepresentation::kWord32, write_barrier_kind));
} else {
store_op = machine()->Store(StoreRepresentation(
MachineRepresentation::kFloat32, write_barrier_kind));
}
LowerStoreOp(rep, node, store_op, rep_type);
break;
}
case IrOpcode::kUnalignedStore: {
MachineRepresentation rep = UnalignedStoreRepresentationOf(node->op());
const Operator* store_op;
if (rep_type == SimdType::kInt32) {
store_op = machine()->UnalignedStore(MachineRepresentation::kWord32);
} else {
store_op = machine()->UnalignedStore(MachineRepresentation::kFloat32);
}
LowerStoreOp(rep, node, store_op, rep_type);
break;
}
case IrOpcode::kReturn: {
DefaultLowering(node);
int new_return_count = GetReturnCountAfterLowering(signature());
......@@ -200,7 +350,7 @@ void SimdScalarLowering::LowerNode(Node* node) {
descriptor->GetReturnType(0) == MachineType::Simd128()) {
// We access the additional return values through projections.
Node* rep_node[kMaxLanes];
for (int i = 0; i < kMaxLanes; i++) {
for (int i = 0; i < kMaxLanes; ++i) {
rep_node[i] =
graph()->NewNode(common()->Projection(i), node, graph()->start());
}
......@@ -214,7 +364,7 @@ void SimdScalarLowering::LowerNode(Node* node) {
// The replacement nodes have already been created, we only have to
// replace placeholder nodes.
Node** rep_node = GetReplacements(node);
for (int i = 0; i < node->op()->ValueInputCount(); i++) {
for (int i = 0; i < node->op()->ValueInputCount(); ++i) {
Node** rep_input =
GetReplacementsWithType(node->InputAt(i), rep_type);
for (int j = 0; j < kMaxLanes; j++) {
......@@ -226,31 +376,29 @@ void SimdScalarLowering::LowerNode(Node* node) {
}
break;
}
case IrOpcode::kInt32x4Add: {
DCHECK(node->InputCount() == 2);
Node** rep_left = GetReplacementsWithType(node->InputAt(0), rep_type);
Node** rep_right = GetReplacementsWithType(node->InputAt(1), rep_type);
Node* rep_node[kMaxLanes];
for (int i = 0; i < kMaxLanes; i++) {
rep_node[i] =
graph()->NewNode(machine()->Int32Add(), rep_left[i], rep_right[i]);
LowerBinaryOp(node, rep_type, machine()->Int32Add());
break;
}
ReplaceNode(node, rep_node);
case IrOpcode::kFloat32x4Add: {
LowerBinaryOp(node, rep_type, machine()->Float32Add());
break;
}
case IrOpcode::kCreateInt32x4: {
case IrOpcode::kCreateInt32x4:
case IrOpcode::kCreateFloat32x4: {
Node* rep_node[kMaxLanes];
for (int i = 0; i < kMaxLanes; i++) {
DCHECK(!HasReplacement(1, node->InputAt(i)));
for (int i = 0; i < kMaxLanes; ++i) {
if (HasReplacement(0, node->InputAt(i))) {
rep_node[i] = GetReplacements(node->InputAt(i))[0];
} else {
rep_node[i] = node->InputAt(i);
}
}
ReplaceNode(node, rep_node);
break;
}
case IrOpcode::kInt32x4ExtractLane: {
case IrOpcode::kInt32x4ExtractLane:
case IrOpcode::kFloat32x4ExtractLane: {
Node* laneNode = node->InputAt(1);
DCHECK_EQ(laneNode->opcode(), IrOpcode::kInt32Constant);
int32_t lane = OpParameter<int32_t>(laneNode);
......@@ -260,41 +408,23 @@ void SimdScalarLowering::LowerNode(Node* node) {
ReplaceNode(node, rep_node);
break;
}
case IrOpcode::kFloat32x4Add: {
DCHECK(node->InputCount() == 2);
Node** rep_left = GetReplacementsWithType(node->InputAt(0), rep_type);
Node** rep_right = GetReplacementsWithType(node->InputAt(1), rep_type);
Node* rep_node[kMaxLanes];
for (int i = 0; i < kMaxLanes; i++) {
rep_node[i] = graph()->NewNode(machine()->Float32Add(), rep_left[i],
rep_right[i]);
}
ReplaceNode(node, rep_node);
break;
}
case IrOpcode::kCreateFloat32x4: {
Node* rep_node[kMaxLanes];
for (int i = 0; i < kMaxLanes; i++) {
DCHECK(!HasReplacement(1, node->InputAt(i)));
rep_node[i] = node->InputAt(i);
}
ReplaceNode(node, rep_node);
break;
}
case IrOpcode::kFloat32x4ExtractLane: {
case IrOpcode::kInt32x4ReplaceLane:
case IrOpcode::kFloat32x4ReplaceLane: {
DCHECK_EQ(3, node->InputCount());
Node* laneNode = node->InputAt(1);
Node* repNode = node->InputAt(2);
DCHECK_EQ(laneNode->opcode(), IrOpcode::kInt32Constant);
int32_t lane = OpParameter<int32_t>(laneNode);
Node* rep_node[kMaxLanes] = {
GetReplacementsWithType(node->InputAt(0), rep_type)[lane], nullptr,
nullptr, nullptr};
DCHECK(lane >= 0 && lane <= 3);
Node** rep_node = GetReplacementsWithType(node->InputAt(0), rep_type);
if (HasReplacement(0, repNode)) {
rep_node[lane] = GetReplacements(repNode)[0];
} else {
rep_node[lane] = repNode;
}
ReplaceNode(node, rep_node);
break;
}
default: { DefaultLowering(node); }
}
}
......@@ -322,7 +452,7 @@ void SimdScalarLowering::ReplaceNode(Node* old, Node** new_node) {
DCHECK(new_node[0] != nullptr ||
(new_node[1] == nullptr && new_node[2] == nullptr &&
new_node[3] == nullptr));
for (int i = 0; i < kMaxLanes; i++) {
for (int i = 0; i < kMaxLanes; ++i) {
replacements_[old->id()].node[i] = new_node[i];
}
}
......@@ -348,7 +478,7 @@ Node** SimdScalarLowering::GetReplacementsWithType(Node* node, SimdType type) {
}
Node** result = zone()->NewArray<Node*>(kMaxLanes);
if (ReplacementType(node) == SimdType::kInt32 && type == SimdType::kFloat32) {
for (int i = 0; i < kMaxLanes; i++) {
for (int i = 0; i < kMaxLanes; ++i) {
if (replacements[i] != nullptr) {
result[i] = graph()->NewNode(machine()->BitcastInt32ToFloat32(),
replacements[i]);
......@@ -357,7 +487,7 @@ Node** SimdScalarLowering::GetReplacementsWithType(Node* node, SimdType type) {
}
}
} else {
for (int i = 0; i < kMaxLanes; i++) {
for (int i = 0; i < kMaxLanes; ++i) {
if (replacements[i] != nullptr) {
result[i] = graph()->NewNode(machine()->BitcastFloat32ToInt32(),
replacements[i]);
......@@ -379,17 +509,17 @@ void SimdScalarLowering::PreparePhiReplacement(Node* phi) {
int value_count = phi->op()->ValueInputCount();
SimdType type = ReplacementType(phi);
Node** inputs_rep[kMaxLanes];
for (int i = 0; i < kMaxLanes; i++) {
for (int i = 0; i < kMaxLanes; ++i) {
inputs_rep[i] = zone()->NewArray<Node*>(value_count + 1);
inputs_rep[i][value_count] = NodeProperties::GetControlInput(phi, 0);
}
for (int i = 0; i < value_count; i++) {
for (int i = 0; i < value_count; ++i) {
for (int j = 0; j < kMaxLanes; j++) {
inputs_rep[j][i] = placeholder_;
}
}
Node* rep_nodes[kMaxLanes];
for (int i = 0; i < kMaxLanes; i++) {
for (int i = 0; i < kMaxLanes; ++i) {
if (type == SimdType::kInt32) {
rep_nodes[i] = graph()->NewNode(
common()->Phi(MachineRepresentation::kWord32, value_count),
......
......@@ -31,6 +31,7 @@ class SimdScalarLowering {
enum class SimdType : uint8_t { kInt32, kFloat32 };
static const int kMaxLanes = 4;
static const int kLaneWidth = 16 / kMaxLanes;
struct Replacement {
Node* node[kMaxLanes];
......@@ -53,6 +54,12 @@ class SimdScalarLowering {
SimdType ReplacementType(Node* node);
void PreparePhiReplacement(Node* phi);
void SetLoweredType(Node* node, Node* output);
void GetIndexNodes(Node* index, Node** new_indices);
void LowerLoadOp(MachineRepresentation rep, Node* node,
const Operator* load_op);
void LowerStoreOp(MachineRepresentation rep, Node* node,
const Operator* store_op, SimdType rep_type);
void LowerBinaryOp(Node* node, SimdType rep_type, const Operator* op);
struct NodeState {
Node* node;
......
......@@ -3124,9 +3124,6 @@ Node* WasmGraphBuilder::SimdOp(wasm::WasmOpcode opcode,
case wasm::kExprI32x4Add:
return graph()->NewNode(jsgraph()->machine()->Int32x4Add(), inputs[0],
inputs[1]);
case wasm::kExprF32x4ExtractLane:
return graph()->NewNode(jsgraph()->machine()->Float32x4ExtractLane(),
inputs[0], inputs[1]);
case wasm::kExprF32x4Splat:
return graph()->NewNode(jsgraph()->machine()->CreateFloat32x4(),
inputs[0], inputs[0], inputs[0], inputs[0]);
......@@ -3152,6 +3149,20 @@ Node* WasmGraphBuilder::SimdExtractLane(wasm::WasmOpcode opcode, uint8_t lane,
}
}
Node* WasmGraphBuilder::SimdReplaceLane(wasm::WasmOpcode opcode, uint8_t lane,
Node* input, Node* replacement) {
switch (opcode) {
case wasm::kExprI32x4ReplaceLane:
return graph()->NewNode(jsgraph()->machine()->Int32x4ReplaceLane(), input,
Int32Constant(lane), replacement);
case wasm::kExprF32x4ReplaceLane:
return graph()->NewNode(jsgraph()->machine()->Float32x4ReplaceLane(),
input, Int32Constant(lane), replacement);
default:
return graph()->NewNode(UnsupportedOpcode(opcode), nullptr);
}
}
static void RecordFunctionCompilation(CodeEventListener::LogEventsAndTags tag,
Isolate* isolate, Handle<Code> code,
const char* message, uint32_t index,
......
......@@ -218,6 +218,8 @@ class WasmGraphBuilder {
Node* SimdOp(wasm::WasmOpcode opcode, const NodeVector& inputs);
Node* SimdExtractLane(wasm::WasmOpcode opcode, uint8_t lane, Node* input);
Node* SimdReplaceLane(wasm::WasmOpcode opcode, uint8_t lane, Node* input,
Node* replacement);
private:
static const int kDefaultBufferSize = 16;
......
......@@ -1338,6 +1338,18 @@ class WasmFullDecoder : public WasmDecoder {
return operand.length;
}
unsigned ReplaceLane(WasmOpcode opcode, LocalType type) {
LaneOperand operand(this, pc_);
if (Validate(pc_, operand)) {
TFNode* input = Pop(0, LocalType::kSimd128).node;
TFNode* replacement = Pop(1, type).node;
TFNode* node =
BUILD(SimdReplaceLane, opcode, operand.lane, input, replacement);
Push(LocalType::kSimd128, node);
}
return operand.length;
}
unsigned DecodeSimdOpcode(WasmOpcode opcode) {
unsigned len = 0;
switch (opcode) {
......@@ -1349,6 +1361,14 @@ class WasmFullDecoder : public WasmDecoder {
len = ExtractLane(opcode, LocalType::kFloat32);
break;
}
case kExprI32x4ReplaceLane: {
len = ReplaceLane(opcode, LocalType::kWord32);
break;
}
case kExprF32x4ReplaceLane: {
len = ReplaceLane(opcode, LocalType::kFloat32);
break;
}
default: {
FunctionSig* sig = WasmOpcodes::Signature(opcode);
if (sig != nullptr) {
......
......@@ -629,6 +629,10 @@ class LocalDeclEncoder {
#define WASM_SIMD_F32x4_EXTRACT_LANE(lane, x) \
x, kSimdPrefix, kExprF32x4ExtractLane & 0xff, static_cast<byte>(lane)
#define WASM_SIMD_F32x4_ADD(x, y) x, y, kSimdPrefix, kExprF32x4Add & 0xff
#define WASM_SIMD_I32x4_REPLACE_LANE(lane, x, y) \
y, x, kSimdPrefix, kExprI32x4ReplaceLane & 0xff, static_cast<byte>(lane)
#define WASM_SIMD_F32x4_REPLACE_LANE(lane, x, y) \
y, x, kSimdPrefix, kExprF32x4ReplaceLane & 0xff, static_cast<byte>(lane)
#define SIG_ENTRY_v_v kWasmFunctionTypeForm, 0, 0
#define SIZEOF_SIG_ENTRY_v_v 3
......
......@@ -276,7 +276,6 @@ const WasmCodePosition kNoCodePosition = -1;
#define FOREACH_SIMD_0_OPERAND_OPCODE(V) \
V(F32x4Splat, 0xe500, s_f) \
V(F32x4ReplaceLane, 0xe502, s_sif) \
V(F32x4Abs, 0xe503, s_s) \
V(F32x4Neg, 0xe504, s_s) \
V(F32x4Sqrt, 0xe505, s_s) \
......@@ -299,7 +298,6 @@ const WasmCodePosition kNoCodePosition = -1;
V(F32x4FromInt32x4, 0xe519, s_s) \
V(F32x4FromUint32x4, 0xe51a, s_s) \
V(I32x4Splat, 0xe51b, s_i) \
V(I32x4ReplaceLane, 0xe51d, s_sii) \
V(I32x4Neg, 0xe51e, s_s) \
V(I32x4Add, 0xe51f, s_ss) \
V(I32x4Sub, 0xe520, s_ss) \
......@@ -327,7 +325,6 @@ const WasmCodePosition kNoCodePosition = -1;
V(I32x4Ge_u, 0xe536, s_ss) \
V(Ui32x4FromFloat32x4, 0xe537, s_s) \
V(I16x8Splat, 0xe538, s_i) \
V(I16x8ReplaceLane, 0xe53a, s_sii) \
V(I16x8Neg, 0xe53b, s_s) \
V(I16x8Add, 0xe53c, s_ss) \
V(I16x8AddSaturate_s, 0xe53d, s_ss) \
......@@ -357,7 +354,6 @@ const WasmCodePosition kNoCodePosition = -1;
V(I16x8Gt_u, 0xe555, s_ss) \
V(I16x8Ge_u, 0xe556, s_ss) \
V(I8x16Splat, 0xe557, s_i) \
V(I8x16ReplaceLane, 0xe559, s_sii) \
V(I8x16Neg, 0xe55a, s_s) \
V(I8x16Add, 0xe55b, s_ss) \
V(I8x16AddSaturate_s, 0xe55c, s_ss) \
......@@ -398,7 +394,11 @@ const WasmCodePosition kNoCodePosition = -1;
V(F32x4ExtractLane, 0xe501, _) \
V(I32x4ExtractLane, 0xe51c, _) \
V(I16x8ExtractLane, 0xe539, _) \
V(I8x16ExtractLane, 0xe558, _)
V(I8x16ExtractLane, 0xe558, _) \
V(F32x4ReplaceLane, 0xe502, _) \
V(I32x4ReplaceLane, 0xe51d, _) \
V(I16x8ReplaceLane, 0xe53a, _) \
V(I8x16ReplaceLane, 0xe559, _)
#define FOREACH_ATOMIC_OPCODE(V) \
V(I32AtomicAdd8S, 0xe601, i_ii) \
......
......@@ -15,7 +15,7 @@ using namespace v8::internal;
using namespace v8::internal::compiler;
using namespace v8::internal::wasm;
WASM_EXEC_TEST(Simd_I32x4_Splat) {
WASM_EXEC_COMPILED_TEST(Simd_I32x4_Splat) {
FLAG_wasm_simd_prototype = true;
WasmRunner<int32_t> r(kExecuteCompiled, MachineType::Int32());
BUILD(r,
......@@ -23,7 +23,7 @@ WASM_EXEC_TEST(Simd_I32x4_Splat) {
FOR_INT32_INPUTS(i) { CHECK_EQ(5, r.Call()); }
}
WASM_EXEC_TEST(Simd_I32x4_Add) {
WASM_EXEC_COMPILED_TEST(Simd_I32x4_Add) {
FLAG_wasm_simd_prototype = true;
WasmRunner<int32_t> r(kExecuteCompiled, MachineType::Int32());
BUILD(r, WASM_SIMD_I32x4_EXTRACT_LANE(
......@@ -32,7 +32,7 @@ WASM_EXEC_TEST(Simd_I32x4_Add) {
FOR_INT32_INPUTS(i) { CHECK_EQ(11, r.Call()); }
}
WASM_EXEC_TEST(Simd_F32x4_Splat) {
WASM_EXEC_COMPILED_TEST(Simd_F32x4_Splat) {
FLAG_wasm_simd_prototype = true;
WasmRunner<int32_t> r(kExecuteCompiled, MachineType::Int32());
BUILD(r,
......@@ -43,7 +43,7 @@ WASM_EXEC_TEST(Simd_F32x4_Splat) {
FOR_INT32_INPUTS(i) { CHECK_EQ(1, r.Call()); }
}
WASM_EXEC_TEST(Simd_I32x4_Extract_With_F32x4) {
WASM_EXEC_COMPILED_TEST(Simd_I32x4_Extract_With_F32x4) {
FLAG_wasm_simd_prototype = true;
WasmRunner<int32_t> r(kExecuteCompiled, MachineType::Int32());
BUILD(r,
......@@ -54,7 +54,7 @@ WASM_EXEC_TEST(Simd_I32x4_Extract_With_F32x4) {
FOR_INT32_INPUTS(i) { CHECK_EQ(1, r.Call()); }
}
WASM_EXEC_TEST(Simd_F32x4_Extract_With_I32x4) {
WASM_EXEC_COMPILED_TEST(Simd_F32x4_Extract_With_I32x4) {
FLAG_wasm_simd_prototype = true;
WasmRunner<int32_t> r(kExecuteCompiled, MachineType::Int32());
BUILD(r,
......@@ -65,7 +65,7 @@ WASM_EXEC_TEST(Simd_F32x4_Extract_With_I32x4) {
FOR_INT32_INPUTS(i) { CHECK_EQ(1, r.Call()); }
}
WASM_EXEC_TEST(Simd_F32x4_Add_With_I32x4) {
WASM_EXEC_COMPILED_TEST(Simd_F32x4_Add_With_I32x4) {
FLAG_wasm_simd_prototype = true;
WasmRunner<int32_t> r(kExecuteCompiled, MachineType::Int32());
BUILD(r,
......@@ -80,7 +80,7 @@ WASM_EXEC_TEST(Simd_F32x4_Add_With_I32x4) {
FOR_INT32_INPUTS(i) { CHECK_EQ(1, r.Call()); }
}
WASM_EXEC_TEST(Simd_I32x4_Add_With_F32x4) {
WASM_EXEC_COMPILED_TEST(Simd_I32x4_Add_With_F32x4) {
FLAG_wasm_simd_prototype = true;
WasmRunner<int32_t> r(kExecuteCompiled, MachineType::Int32());
BUILD(r,
......@@ -94,3 +94,224 @@ WASM_EXEC_TEST(Simd_I32x4_Add_With_F32x4) {
WASM_RETURN1(WASM_I32V(1)), WASM_RETURN1(WASM_I32V(0))));
FOR_INT32_INPUTS(i) { CHECK_EQ(1, r.Call()); }
}
WASM_EXEC_COMPILED_TEST(Simd_I32x4_Local) {
FLAG_wasm_simd_prototype = true;
WasmRunner<int32_t> r(kExecuteCompiled, MachineType::Int32());
r.AllocateLocal(kAstS128);
BUILD(r, WASM_BLOCK(WASM_SET_LOCAL(1, WASM_SIMD_I32x4_SPLAT(WASM_I32V(31))),
WASM_RETURN1(
WASM_SIMD_I32x4_EXTRACT_LANE(0, WASM_GET_LOCAL(1)))));
FOR_INT32_INPUTS(i) { CHECK_EQ(31, r.Call()); }
}
WASM_EXEC_COMPILED_TEST(Simd_I32x4_Replace_Lane) {
FLAG_wasm_simd_prototype = true;
WasmRunner<int32_t> r(kExecuteCompiled, MachineType::Int32());
r.AllocateLocal(kAstS128);
BUILD(r,
WASM_BLOCK(
WASM_SET_LOCAL(1, WASM_SIMD_I32x4_SPLAT(WASM_I32V(31))),
WASM_SET_LOCAL(1, WASM_SIMD_I32x4_REPLACE_LANE(2, WASM_GET_LOCAL(1),
WASM_I32V(53))),
WASM_RETURN1(WASM_SIMD_I32x4_EXTRACT_LANE(2, WASM_GET_LOCAL(1)))));
FOR_INT32_INPUTS(i) { CHECK_EQ(53, r.Call()); }
}
WASM_EXEC_COMPILED_TEST(Simd_F32x4_Replace_Lane) {
FLAG_wasm_simd_prototype = true;
WasmRunner<int32_t> r(kExecuteCompiled, MachineType::Int32());
r.AllocateLocal(kAstF32);
r.AllocateLocal(kAstS128);
BUILD(r, WASM_BLOCK(
WASM_SET_LOCAL(2, WASM_SIMD_F32x4_SPLAT(WASM_F32(23.5))),
WASM_SET_LOCAL(2, WASM_SIMD_F32x4_REPLACE_LANE(
3, WASM_GET_LOCAL(2), WASM_F32(65.25))),
WASM_SET_LOCAL(
1, WASM_SIMD_F32x4_EXTRACT_LANE(3, WASM_GET_LOCAL(2))),
WASM_IF(WASM_F32_EQ(WASM_GET_LOCAL(1), WASM_F32(65.25)),
WASM_RETURN1(WASM_I32V(1))),
WASM_RETURN1(WASM_I32V(0))));
FOR_INT32_INPUTS(i) { CHECK_EQ(1, r.Call()); }
}
WASM_EXEC_COMPILED_TEST(Simd_I32x4_Splat_From_Extract) {
FLAG_wasm_simd_prototype = true;
WasmRunner<int32_t> r(kExecuteCompiled, MachineType::Int32());
r.AllocateLocal(kAstI32);
r.AllocateLocal(kAstS128);
BUILD(r,
WASM_BLOCK(
WASM_SET_LOCAL(1, WASM_SIMD_I32x4_EXTRACT_LANE(
0, WASM_SIMD_I32x4_SPLAT(WASM_I32V(76)))),
WASM_SET_LOCAL(2, WASM_SIMD_I32x4_SPLAT(WASM_GET_LOCAL(1))),
WASM_RETURN1(WASM_SIMD_I32x4_EXTRACT_LANE(1, WASM_GET_LOCAL(2)))));
FOR_INT32_INPUTS(i) { CHECK_EQ(76, r.Call()); }
}
WASM_EXEC_COMPILED_TEST(Simd_I32x4_Get_Global) {
FLAG_wasm_simd_prototype = true;
TestingModule module(kExecuteCompiled);
int32_t* global = module.AddGlobal<int32_t>(kAstS128);
*(global) = 0;
*(global + 1) = 1;
*(global + 2) = 2;
*(global + 3) = 3;
WasmRunner<int32_t> r(&module, MachineType::Int32());
r.AllocateLocal(kAstI32);
BUILD(r, WASM_BLOCK(
WASM_SET_LOCAL(1, WASM_I32V(1)),
WASM_IF(WASM_I32_NE(WASM_I32V(0), WASM_SIMD_I32x4_EXTRACT_LANE(
0, WASM_GET_GLOBAL(0))),
WASM_SET_LOCAL(1, WASM_I32V(0))),
WASM_IF(WASM_I32_NE(WASM_I32V(1), WASM_SIMD_I32x4_EXTRACT_LANE(
1, WASM_GET_GLOBAL(0))),
WASM_SET_LOCAL(1, WASM_I32V(0))),
WASM_IF(WASM_I32_NE(WASM_I32V(2), WASM_SIMD_I32x4_EXTRACT_LANE(
2, WASM_GET_GLOBAL(0))),
WASM_SET_LOCAL(1, WASM_I32V(0))),
WASM_IF(WASM_I32_NE(WASM_I32V(3), WASM_SIMD_I32x4_EXTRACT_LANE(
3, WASM_GET_GLOBAL(0))),
WASM_SET_LOCAL(1, WASM_I32V(0))),
WASM_RETURN1(WASM_GET_LOCAL(1))));
FOR_INT32_INPUTS(i) { CHECK_EQ(1, r.Call(0)); }
}
WASM_EXEC_COMPILED_TEST(Simd_I32x4_Set_Global) {
FLAG_wasm_simd_prototype = true;
TestingModule module(kExecuteCompiled);
int32_t* global = module.AddGlobal<int32_t>(kAstS128);
WasmRunner<int32_t> r(&module, MachineType::Int32());
BUILD(r, WASM_BLOCK(
WASM_SET_GLOBAL(0, WASM_SIMD_I32x4_SPLAT(WASM_I32V(23))),
WASM_SET_GLOBAL(0, WASM_SIMD_I32x4_REPLACE_LANE(
1, WASM_GET_GLOBAL(0), WASM_I32V(34))),
WASM_SET_GLOBAL(0, WASM_SIMD_I32x4_REPLACE_LANE(
2, WASM_GET_GLOBAL(0), WASM_I32V(45))),
WASM_SET_GLOBAL(0, WASM_SIMD_I32x4_REPLACE_LANE(
3, WASM_GET_GLOBAL(0), WASM_I32V(56))),
WASM_RETURN1(WASM_I32V(1))));
FOR_INT32_INPUTS(i) { CHECK_EQ(1, r.Call(0)); }
CHECK_EQ(*global, 23);
CHECK_EQ(*(global + 1), 34);
CHECK_EQ(*(global + 2), 45);
CHECK_EQ(*(global + 3), 56);
}
WASM_EXEC_COMPILED_TEST(Simd_F32x4_Get_Global) {
FLAG_wasm_simd_prototype = true;
TestingModule module(kExecuteCompiled);
float* global = module.AddGlobal<float>(kAstS128);
*(global) = 0.0;
*(global + 1) = 1.5;
*(global + 2) = 2.25;
*(global + 3) = 3.5;
WasmRunner<int32_t> r(&module, MachineType::Int32());
r.AllocateLocal(kAstI32);
BUILD(r, WASM_BLOCK(
WASM_SET_LOCAL(1, WASM_I32V(1)),
WASM_IF(WASM_F32_NE(WASM_F32(0.0), WASM_SIMD_F32x4_EXTRACT_LANE(
0, WASM_GET_GLOBAL(0))),
WASM_SET_LOCAL(1, WASM_I32V(0))),
WASM_IF(WASM_F32_NE(WASM_F32(1.5), WASM_SIMD_F32x4_EXTRACT_LANE(
1, WASM_GET_GLOBAL(0))),
WASM_SET_LOCAL(1, WASM_I32V(0))),
WASM_IF(WASM_F32_NE(WASM_F32(2.25), WASM_SIMD_F32x4_EXTRACT_LANE(
2, WASM_GET_GLOBAL(0))),
WASM_SET_LOCAL(1, WASM_I32V(0))),
WASM_IF(WASM_F32_NE(WASM_F32(3.5), WASM_SIMD_F32x4_EXTRACT_LANE(
3, WASM_GET_GLOBAL(0))),
WASM_SET_LOCAL(1, WASM_I32V(0))),
WASM_RETURN1(WASM_GET_LOCAL(1))));
FOR_INT32_INPUTS(i) { CHECK_EQ(1, r.Call(0)); }
}
WASM_EXEC_COMPILED_TEST(Simd_F32x4_Set_Global) {
FLAG_wasm_simd_prototype = true;
TestingModule module(kExecuteCompiled);
float* global = module.AddGlobal<float>(kAstS128);
WasmRunner<int32_t> r(&module, MachineType::Int32());
BUILD(r, WASM_BLOCK(
WASM_SET_GLOBAL(0, WASM_SIMD_F32x4_SPLAT(WASM_F32(13.5))),
WASM_SET_GLOBAL(0, WASM_SIMD_F32x4_REPLACE_LANE(
1, WASM_GET_GLOBAL(0), WASM_F32(45.5))),
WASM_SET_GLOBAL(0, WASM_SIMD_F32x4_REPLACE_LANE(
2, WASM_GET_GLOBAL(0), WASM_F32(32.25))),
WASM_SET_GLOBAL(0, WASM_SIMD_F32x4_REPLACE_LANE(
3, WASM_GET_GLOBAL(0), WASM_F32(65.0))),
WASM_RETURN1(WASM_I32V(1))));
FOR_INT32_INPUTS(i) { CHECK_EQ(1, r.Call(0)); }
CHECK_EQ(*global, 13.5);
CHECK_EQ(*(global + 1), 45.5);
CHECK_EQ(*(global + 2), 32.25);
CHECK_EQ(*(global + 3), 65.0);
}
WASM_EXEC_COMPILED_TEST(Simd_I32x4_For) {
FLAG_wasm_simd_prototype = true;
WasmRunner<int32_t> r(kExecuteCompiled, MachineType::Int32());
r.AllocateLocal(kAstI32);
r.AllocateLocal(kAstS128);
BUILD(
r,
WASM_BLOCK(
WASM_SET_LOCAL(2, WASM_SIMD_I32x4_SPLAT(WASM_I32V(31))),
WASM_SET_LOCAL(2, WASM_SIMD_I32x4_REPLACE_LANE(1, WASM_GET_LOCAL(2),
WASM_I32V(53))),
WASM_SET_LOCAL(2, WASM_SIMD_I32x4_REPLACE_LANE(2, WASM_GET_LOCAL(2),
WASM_I32V(23))),
WASM_SET_LOCAL(1, WASM_I32V(0)),
WASM_LOOP(WASM_SET_LOCAL(2, WASM_SIMD_I32x4_ADD(
WASM_GET_LOCAL(2),
WASM_SIMD_I32x4_SPLAT(WASM_I32V(1)))),
WASM_IF(WASM_I32_NE(WASM_INC_LOCAL(1), WASM_I32V(5)),
WASM_BR(1))),
WASM_SET_LOCAL(1, WASM_I32V(1)),
WASM_IF(
WASM_I32_NE(WASM_SIMD_I32x4_EXTRACT_LANE(0, WASM_GET_LOCAL(2)),
WASM_I32V(36)),
WASM_SET_LOCAL(1, WASM_I32V(0))),
WASM_IF(
WASM_I32_NE(WASM_SIMD_I32x4_EXTRACT_LANE(1, WASM_GET_LOCAL(2)),
WASM_I32V(58)),
WASM_SET_LOCAL(1, WASM_I32V(0))),
WASM_IF(
WASM_I32_NE(WASM_SIMD_I32x4_EXTRACT_LANE(2, WASM_GET_LOCAL(2)),
WASM_I32V(28)),
WASM_SET_LOCAL(1, WASM_I32V(0))),
WASM_IF(
WASM_I32_NE(WASM_SIMD_I32x4_EXTRACT_LANE(3, WASM_GET_LOCAL(2)),
WASM_I32V(36)),
WASM_SET_LOCAL(1, WASM_I32V(0))),
WASM_RETURN1(WASM_GET_LOCAL(1))));
FOR_INT32_INPUTS(i) { CHECK_EQ(1, r.Call()); }
}
WASM_EXEC_COMPILED_TEST(Simd_F32x4_For) {
FLAG_wasm_simd_prototype = true;
WasmRunner<int32_t> r(kExecuteCompiled, MachineType::Int32());
r.AllocateLocal(kAstI32);
r.AllocateLocal(kAstS128);
BUILD(r, WASM_BLOCK(
WASM_SET_LOCAL(2, WASM_SIMD_F32x4_SPLAT(WASM_F32(21.25))),
WASM_SET_LOCAL(2, WASM_SIMD_F32x4_REPLACE_LANE(
3, WASM_GET_LOCAL(2), WASM_F32(19.5))),
WASM_SET_LOCAL(1, WASM_I32V(0)),
WASM_LOOP(
WASM_SET_LOCAL(2, WASM_SIMD_F32x4_ADD(
WASM_GET_LOCAL(2),
WASM_SIMD_F32x4_SPLAT(WASM_F32(2.0)))),
WASM_IF(WASM_I32_NE(WASM_INC_LOCAL(1), WASM_I32V(3)),
WASM_BR(1))),
WASM_SET_LOCAL(1, WASM_I32V(1)),
WASM_IF(WASM_F32_NE(
WASM_SIMD_F32x4_EXTRACT_LANE(0, WASM_GET_LOCAL(2)),
WASM_F32(27.25)),
WASM_SET_LOCAL(1, WASM_I32V(0))),
WASM_IF(WASM_F32_NE(
WASM_SIMD_F32x4_EXTRACT_LANE(3, WASM_GET_LOCAL(2)),
WASM_F32(25.5)),
WASM_SET_LOCAL(1, WASM_I32V(0))),
WASM_RETURN1(WASM_GET_LOCAL(1))));
FOR_INT32_INPUTS(i) { CHECK_EQ(1, r.Call()); }
}
......@@ -791,15 +791,17 @@ class WasmRunner {
};
// A macro to define tests that run in different engine configurations.
// Currently only supports compiled tests, but a future
// RunWasmInterpreted_##name version will allow each test to also run in the
// interpreter.
#define WASM_EXEC_TEST(name) \
void RunWasm_##name(WasmExecutionMode execution_mode); \
TEST(RunWasmCompiled_##name) { RunWasm_##name(kExecuteCompiled); } \
TEST(RunWasmInterpreted_##name) { RunWasm_##name(kExecuteInterpreted); } \
void RunWasm_##name(WasmExecutionMode execution_mode)
#define WASM_EXEC_COMPILED_TEST(name) \
void RunWasm_##name(WasmExecutionMode execution_mode); \
TEST(RunWasmCompiled_##name) { RunWasm_##name(kExecuteCompiled); } \
void RunWasm_##name(WasmExecutionMode execution_mode)
} // namespace
#endif
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment