Commit 02c6b041 authored by gdeepti's avatar gdeepti Committed by Commit bot

[wasm] Implement I32x4ReplaceLane, I32x4Add, I32x4Sub.

R=bbudge@chromium.org, titzer@chromium.org

Review-Url: https://codereview.chromium.org/2385393002
Cr-Commit-Position: refs/heads/master@{#41505}
parent f5cb17a8
......@@ -1131,6 +1131,43 @@ const Operator* CommonOperatorBuilder::ResizeMergeOrPhi(const Operator* op,
}
}
const Operator* CommonOperatorBuilder::Int32x4ExtractLane(int32_t lane_number) {
DCHECK(0 <= lane_number && lane_number < 4);
return new (zone()) Operator1<int32_t>( // --
IrOpcode::kInt32x4ExtractLane, Operator::kPure, // opcode
"Int32x4ExtractLane", // name
1, 0, 0, 1, 0, 0, // counts
lane_number); // parameter
}
const Operator* CommonOperatorBuilder::Int32x4ReplaceLane(int32_t lane_number) {
DCHECK(0 <= lane_number && lane_number < 4);
return new (zone()) Operator1<int32_t>( // --
IrOpcode::kInt32x4ReplaceLane, Operator::kPure, // opcode
"Int32x4ReplaceLane", // name
2, 0, 0, 1, 0, 0, // counts
lane_number); // parameter
}
const Operator* CommonOperatorBuilder::Float32x4ExtractLane(
int32_t lane_number) {
DCHECK(0 <= lane_number && lane_number < 4);
return new (zone()) Operator1<int32_t>( // --
IrOpcode::kFloat32x4ExtractLane, Operator::kPure, // opcode
"Float32x4ExtractLane", // name
1, 0, 0, 1, 0, 0, // counts
lane_number); // parameter
}
const Operator* CommonOperatorBuilder::Float32x4ReplaceLane(
int32_t lane_number) {
DCHECK(0 <= lane_number && lane_number < 4);
return new (zone()) Operator1<int32_t>( // --
IrOpcode::kFloat32x4ReplaceLane, Operator::kPure, // opcode
"Float32x4ReplaceLane", // name
2, 0, 0, 1, 0, 0, // counts
lane_number); // parameter
}
const FrameStateFunctionInfo*
CommonOperatorBuilder::CreateFrameStateFunctionInfo(
......
......@@ -260,6 +260,12 @@ class V8_EXPORT_PRIVATE CommonOperatorBuilder final
// with {size} inputs.
const Operator* ResizeMergeOrPhi(const Operator* op, int size);
// Simd Operators
const Operator* Int32x4ExtractLane(int32_t);
const Operator* Int32x4ReplaceLane(int32_t);
const Operator* Float32x4ExtractLane(int32_t);
const Operator* Float32x4ReplaceLane(int32_t);
// Constructs function info for frame state construction.
const FrameStateFunctionInfo* CreateFrameStateFunctionInfo(
FrameStateType type, int parameter_count, int local_count,
......
......@@ -1396,6 +1396,12 @@ void InstructionSelector::VisitNode(Node* node) {
return MarkAsSimd128(node), VisitCreateInt32x4(node);
case IrOpcode::kInt32x4ExtractLane:
return MarkAsWord32(node), VisitInt32x4ExtractLane(node);
case IrOpcode::kInt32x4ReplaceLane:
return MarkAsSimd128(node), VisitInt32x4ReplaceLane(node);
case IrOpcode::kInt32x4Add:
return MarkAsSimd128(node), VisitInt32x4Add(node);
case IrOpcode::kInt32x4Sub:
return MarkAsSimd128(node), VisitInt32x4Sub(node);
default:
V8_Fatal(__FILE__, __LINE__, "Unexpected operator #%d:%s @ node #%d",
node->opcode(), node->op()->mnemonic(), node->id());
......@@ -1729,6 +1735,14 @@ void InstructionSelector::VisitCreateInt32x4(Node* node) { UNIMPLEMENTED(); }
void InstructionSelector::VisitInt32x4ExtractLane(Node* node) {
UNIMPLEMENTED();
}
void InstructionSelector::VisitInt32x4ReplaceLane(Node* node) {
UNIMPLEMENTED();
}
void InstructionSelector::VisitInt32x4Add(Node* node) { UNIMPLEMENTED(); }
void InstructionSelector::VisitInt32x4Sub(Node* node) { UNIMPLEMENTED(); }
#endif // !V8_TARGET_ARCH_X64
void InstructionSelector::VisitFinishRegion(Node* node) { EmitIdentity(node); }
......
......@@ -399,9 +399,7 @@ void SimdScalarLowering::LowerNode(Node* node) {
}
case IrOpcode::kInt32x4ExtractLane:
case IrOpcode::kFloat32x4ExtractLane: {
Node* laneNode = node->InputAt(1);
DCHECK_EQ(laneNode->opcode(), IrOpcode::kInt32Constant);
int32_t lane = OpParameter<int32_t>(laneNode);
int32_t lane = OpParameter<int32_t>(node);
Node* rep_node[kMaxLanes] = {
GetReplacementsWithType(node->InputAt(0), rep_type)[lane], nullptr,
nullptr, nullptr};
......@@ -410,11 +408,9 @@ void SimdScalarLowering::LowerNode(Node* node) {
}
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);
DCHECK_EQ(2, node->InputCount());
Node* repNode = node->InputAt(1);
int32_t lane = OpParameter<int32_t>(node);
DCHECK(lane >= 0 && lane <= 3);
Node** rep_node = GetReplacementsWithType(node->InputAt(0), rep_type);
if (HasReplacement(0, repNode)) {
......
......@@ -3124,6 +3124,9 @@ Node* WasmGraphBuilder::SimdOp(wasm::WasmOpcode opcode,
case wasm::kExprI32x4Add:
return graph()->NewNode(jsgraph()->machine()->Int32x4Add(), inputs[0],
inputs[1]);
case wasm::kExprI32x4Sub:
return graph()->NewNode(jsgraph()->machine()->Int32x4Sub(), inputs[0],
inputs[1]);
case wasm::kExprF32x4Splat:
return graph()->NewNode(jsgraph()->machine()->CreateFloat32x4(),
inputs[0], inputs[0], inputs[0], inputs[0]);
......@@ -3135,29 +3138,21 @@ Node* WasmGraphBuilder::SimdOp(wasm::WasmOpcode opcode,
}
}
Node* WasmGraphBuilder::SimdExtractLane(wasm::WasmOpcode opcode, uint8_t lane,
Node* input) {
Node* WasmGraphBuilder::SimdLaneOp(wasm::WasmOpcode opcode, uint8_t lane,
const NodeVector& inputs) {
switch (opcode) {
case wasm::kExprI32x4ExtractLane:
return graph()->NewNode(jsgraph()->machine()->Int32x4ExtractLane(), input,
Int32Constant(lane));
case wasm::kExprF32x4ExtractLane:
return graph()->NewNode(jsgraph()->machine()->Float32x4ExtractLane(),
input, Int32Constant(lane));
default:
return graph()->NewNode(UnsupportedOpcode(opcode), nullptr);
}
}
Node* WasmGraphBuilder::SimdReplaceLane(wasm::WasmOpcode opcode, uint8_t lane,
Node* input, Node* replacement) {
switch (opcode) {
return graph()->NewNode(jsgraph()->common()->Int32x4ExtractLane(lane),
inputs[0]);
case wasm::kExprI32x4ReplaceLane:
return graph()->NewNode(jsgraph()->machine()->Int32x4ReplaceLane(), input,
Int32Constant(lane), replacement);
return graph()->NewNode(jsgraph()->common()->Int32x4ReplaceLane(lane),
inputs[0], inputs[1]);
case wasm::kExprF32x4ExtractLane:
return graph()->NewNode(jsgraph()->common()->Float32x4ExtractLane(lane),
inputs[0]);
case wasm::kExprF32x4ReplaceLane:
return graph()->NewNode(jsgraph()->machine()->Float32x4ReplaceLane(),
input, Int32Constant(lane), replacement);
return graph()->NewNode(jsgraph()->common()->Float32x4ReplaceLane(lane),
inputs[0], inputs[1]);
default:
return graph()->NewNode(UnsupportedOpcode(opcode), nullptr);
}
......
......@@ -217,9 +217,9 @@ class WasmGraphBuilder {
Node* CreateS128Value(int32_t value);
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);
Node* SimdLaneOp(wasm::WasmOpcode opcode, uint8_t lane,
const NodeVector& inputs);
private:
static const int kDefaultBufferSize = 16;
......
......@@ -2147,6 +2147,26 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
__ Pextrd(i.OutputRegister(), i.InputSimd128Register(0), i.InputInt8(1));
break;
}
case kX64Int32x4ReplaceLane: {
CpuFeatureScope sse_scope(masm(), SSE4_1);
if (instr->InputAt(2)->IsRegister()) {
__ Pinsrd(i.OutputSimd128Register(), i.InputRegister(2),
i.InputInt8(1));
} else {
__ Pinsrd(i.OutputSimd128Register(), i.InputOperand(2), i.InputInt8(1));
}
break;
}
case kX64Int32x4Add: {
CpuFeatureScope sse_scope(masm(), SSE4_1);
__ paddd(i.OutputSimd128Register(), i.InputSimd128Register(1));
break;
}
case kX64Int32x4Sub: {
CpuFeatureScope sse_scope(masm(), SSE4_1);
__ psubd(i.OutputSimd128Register(), i.InputSimd128Register(1));
break;
}
case kCheckedLoadInt8:
ASSEMBLE_CHECKED_LOAD_INTEGER(movsxbl);
break;
......
......@@ -147,7 +147,10 @@ namespace compiler {
V(X64Xchgw) \
V(X64Xchgl) \
V(X64Int32x4Create) \
V(X64Int32x4ExtractLane)
V(X64Int32x4ExtractLane) \
V(X64Int32x4ReplaceLane) \
V(X64Int32x4Add) \
V(X64Int32x4Sub)
// Addressing modes represent the "shape" of inputs to an instruction.
// Many instructions support multiple addressing modes. Addressing modes
......
......@@ -125,6 +125,9 @@ int InstructionScheduler::GetTargetInstructionFlags(
case kX64Inc32:
case kX64Int32x4Create:
case kX64Int32x4ExtractLane:
case kX64Int32x4ReplaceLane:
case kX64Int32x4Add:
case kX64Int32x4Sub:
return (instr->addressing_mode() == kMode_None)
? kNoOpcodeFlags
: kIsLoadOperation | kHasSideEffect;
......
......@@ -2379,8 +2379,29 @@ void InstructionSelector::VisitCreateInt32x4(Node* node) {
void InstructionSelector::VisitInt32x4ExtractLane(Node* node) {
X64OperandGenerator g(this);
int32_t lane = OpParameter<int32_t>(node);
Emit(kX64Int32x4ExtractLane, g.DefineAsRegister(node),
g.UseRegister(node->InputAt(0)), g.UseImmediate(node->InputAt(1)));
g.UseRegister(node->InputAt(0)), g.UseImmediate(lane));
}
void InstructionSelector::VisitInt32x4ReplaceLane(Node* node) {
X64OperandGenerator g(this);
int32_t lane = OpParameter<int32_t>(node);
Emit(kX64Int32x4ReplaceLane, g.DefineSameAsFirst(node),
g.UseRegister(node->InputAt(0)), g.UseImmediate(lane),
g.Use(node->InputAt(1)));
}
void InstructionSelector::VisitInt32x4Add(Node* node) {
X64OperandGenerator g(this);
Emit(kX64Int32x4Add, g.DefineSameAsFirst(node),
g.UseRegister(node->InputAt(0)), g.UseRegister(node->InputAt(1)));
}
void InstructionSelector::VisitInt32x4Sub(Node* node) {
X64OperandGenerator g(this);
Emit(kX64Int32x4Sub, g.DefineSameAsFirst(node),
g.UseRegister(node->InputAt(0)), g.UseRegister(node->InputAt(1)));
}
// static
......
......@@ -1331,8 +1331,9 @@ class WasmFullDecoder : public WasmDecoder {
unsigned ExtractLane(WasmOpcode opcode, LocalType type) {
LaneOperand operand(this, pc_);
if (Validate(pc_, operand)) {
TFNode* input = Pop(0, LocalType::kSimd128).node;
TFNode* node = BUILD(SimdExtractLane, opcode, operand.lane, input);
compiler::NodeVector inputs(1, zone_);
inputs[0] = Pop(0, LocalType::kSimd128).node;
TFNode* node = BUILD(SimdLaneOp, opcode, operand.lane, inputs);
Push(type, node);
}
return operand.length;
......@@ -1341,10 +1342,10 @@ class WasmFullDecoder : public WasmDecoder {
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);
compiler::NodeVector inputs(2, zone_);
inputs[1] = Pop(1, type).node;
inputs[0] = Pop(0, LocalType::kSimd128).node;
TFNode* node = BUILD(SimdLaneOp, opcode, operand.lane, inputs);
Push(LocalType::kSimd128, node);
}
return operand.length;
......
......@@ -624,15 +624,16 @@ class LocalDeclEncoder {
#define WASM_SIMD_I32x4_SPLAT(x) x, kSimdPrefix, kExprI32x4Splat & 0xff
#define WASM_SIMD_I32x4_EXTRACT_LANE(lane, x) \
x, kSimdPrefix, kExprI32x4ExtractLane & 0xff, static_cast<byte>(lane)
#define WASM_SIMD_I32x4_REPLACE_LANE(lane, x, y) \
x, y, kSimdPrefix, kExprI32x4ReplaceLane & 0xff, static_cast<byte>(lane)
#define WASM_SIMD_I32x4_ADD(x, y) x, y, kSimdPrefix, kExprI32x4Add & 0xff
#define WASM_SIMD_I32x4_SUB(x, y) x, y, kSimdPrefix, kExprI32x4Sub & 0xff
#define WASM_SIMD_F32x4_SPLAT(x) x, kSimdPrefix, kExprF32x4Splat & 0xff
#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)
x, y, kSimdPrefix, kExprF32x4ReplaceLane & 0xff, static_cast<byte>(lane)
#define SIG_ENTRY_v_v kWasmFunctionTypeForm, 0, 0
#define SIZEOF_SIG_ENTRY_v_v 3
......
......@@ -392,11 +392,11 @@ const WasmCodePosition kNoCodePosition = -1;
#define FOREACH_SIMD_1_OPERAND_OPCODE(V) \
V(F32x4ExtractLane, 0xe501, _) \
V(F32x4ReplaceLane, 0xe502, _) \
V(I32x4ExtractLane, 0xe51c, _) \
V(I32x4ReplaceLane, 0xe51d, _) \
V(I16x8ExtractLane, 0xe539, _) \
V(I8x16ExtractLane, 0xe558, _) \
V(F32x4ReplaceLane, 0xe502, _) \
V(I32x4ReplaceLane, 0xe51d, _) \
V(I16x8ReplaceLane, 0xe53a, _) \
V(I8x16ReplaceLane, 0xe559, _)
......@@ -484,11 +484,9 @@ const WasmCodePosition kNoCodePosition = -1;
#define FOREACH_SIMD_SIGNATURE(V) \
V(s_s, kAstS128, kAstS128) \
V(s_f, kAstS128, kAstF32) \
V(s_sif, kAstS128, kAstS128, kAstI32, kAstF32) \
V(s_ss, kAstS128, kAstS128, kAstS128) \
V(s_sss, kAstS128, kAstS128, kAstS128, kAstS128) \
V(s_i, kAstS128, kAstI32) \
V(s_sii, kAstS128, kAstS128, kAstI32, kAstI32) \
V(s_si, kAstS128, kAstS128, kAstI32)
#define FOREACH_PREFIX(V) \
......
......@@ -13,7 +13,26 @@ using namespace v8::internal;
using namespace v8::internal::compiler;
using namespace v8::internal::wasm;
WASM_EXEC_TEST(Splat) {
// TODO(gdeepti): These are tests using sample values to verify functional
// correctness of opcodes, add more tests for a range of values and macroize
// tests.
#define WASM_SIMD_CHECK_LANE(TYPE, value, LANE_TYPE, lane_value, lane_index) \
WASM_IF(WASM_##LANE_TYPE##_NE(WASM_GET_LOCAL(lane_value), \
WASM_SIMD_##TYPE##_EXTRACT_LANE( \
lane_index, WASM_GET_LOCAL(value))), \
WASM_RETURN1(WASM_ZERO))
#define WASM_SIMD_CHECK4(TYPE, value, LANE_TYPE, lv0, lv1, lv2, lv3) \
WASM_SIMD_CHECK_LANE(TYPE, value, LANE_TYPE, lv0, 0) \
, WASM_SIMD_CHECK_LANE(TYPE, value, LANE_TYPE, lv1, 1), \
WASM_SIMD_CHECK_LANE(TYPE, value, LANE_TYPE, lv2, 2), \
WASM_SIMD_CHECK_LANE(TYPE, value, LANE_TYPE, lv3, 3)
#define WASM_SIMD_CHECK_SPLAT4(TYPE, value, LANE_TYPE, lv) \
WASM_SIMD_CHECK4(TYPE, value, LANE_TYPE, lv, lv, lv, lv)
WASM_EXEC_TEST(I32x4Splat) {
FLAG_wasm_simd_prototype = true;
// Store SIMD value in a local variable, use extract lane to check lane values
......@@ -27,23 +46,92 @@ WASM_EXEC_TEST(Splat) {
//
// return 1
WasmRunner<int32_t> r(kExecuteCompiled, MachineType::Int32());
r.AllocateLocal(kAstS128);
byte lane_val = 0;
byte simd = r.AllocateLocal(kAstS128);
BUILD(r, WASM_BLOCK(WASM_SET_LOCAL(simd, WASM_SIMD_I32x4_SPLAT(
WASM_GET_LOCAL(lane_val))),
WASM_SIMD_CHECK_SPLAT4(I32x4, simd, I32, lane_val),
WASM_RETURN1(WASM_ONE)));
FOR_INT32_INPUTS(i) { CHECK_EQ(1, r.Call(*i)); }
}
WASM_EXEC_TEST(I32x4ReplaceLane) {
FLAG_wasm_simd_prototype = true;
WasmRunner<int32_t> r(kExecuteCompiled, MachineType::Int32(),
MachineType::Int32());
byte old_val = 0;
byte new_val = 1;
byte simd = r.AllocateLocal(kAstS128);
BUILD(r, WASM_BLOCK(
WASM_SET_LOCAL(simd,
WASM_SIMD_I32x4_SPLAT(WASM_GET_LOCAL(old_val))),
WASM_SET_LOCAL(
simd, WASM_SIMD_I32x4_REPLACE_LANE(0, WASM_GET_LOCAL(simd),
WASM_GET_LOCAL(new_val))),
WASM_SIMD_CHECK4(I32x4, simd, I32, new_val, old_val, old_val,
old_val),
WASM_SET_LOCAL(
simd, WASM_SIMD_I32x4_REPLACE_LANE(1, WASM_GET_LOCAL(simd),
WASM_GET_LOCAL(new_val))),
WASM_SIMD_CHECK4(I32x4, simd, I32, new_val, new_val, old_val,
old_val),
WASM_SET_LOCAL(
simd, WASM_SIMD_I32x4_REPLACE_LANE(2, WASM_GET_LOCAL(simd),
WASM_GET_LOCAL(new_val))),
WASM_SIMD_CHECK4(I32x4, simd, I32, new_val, new_val, new_val,
old_val),
WASM_SET_LOCAL(
simd, WASM_SIMD_I32x4_REPLACE_LANE(3, WASM_GET_LOCAL(simd),
WASM_GET_LOCAL(new_val))),
WASM_SIMD_CHECK_SPLAT4(I32x4, simd, I32, new_val),
WASM_RETURN1(WASM_ONE)));
CHECK_EQ(1, r.Call(1, 2));
}
WASM_EXEC_TEST(I32x4Add) {
FLAG_wasm_simd_prototype = true;
WasmRunner<int32_t> r(kExecuteCompiled, MachineType::Int32(),
MachineType::Int32(), MachineType::Int32());
byte a = 0;
byte b = 1;
byte expected = 2;
byte simd0 = r.AllocateLocal(kAstS128);
byte simd1 = r.AllocateLocal(kAstS128);
BUILD(r,
WASM_BLOCK(
WASM_SET_LOCAL(1, WASM_SIMD_I32x4_SPLAT(WASM_GET_LOCAL(0))),
WASM_IF(WASM_I32_NE(WASM_GET_LOCAL(0), WASM_SIMD_I32x4_EXTRACT_LANE(
0, WASM_GET_LOCAL(1))),
WASM_RETURN1(WASM_ZERO)),
WASM_IF(WASM_I32_NE(WASM_GET_LOCAL(0), WASM_SIMD_I32x4_EXTRACT_LANE(
1, WASM_GET_LOCAL(1))),
WASM_RETURN1(WASM_ZERO)),
WASM_IF(WASM_I32_NE(WASM_GET_LOCAL(0), WASM_SIMD_I32x4_EXTRACT_LANE(
2, WASM_GET_LOCAL(1))),
WASM_RETURN1(WASM_ZERO)),
WASM_IF(WASM_I32_NE(WASM_GET_LOCAL(0), WASM_SIMD_I32x4_EXTRACT_LANE(
3, WASM_GET_LOCAL(1))),
WASM_RETURN1(WASM_ZERO)),
WASM_SET_LOCAL(simd0, WASM_SIMD_I32x4_SPLAT(WASM_GET_LOCAL(a))),
WASM_SET_LOCAL(simd1, WASM_SIMD_I32x4_SPLAT(WASM_GET_LOCAL(b))),
WASM_SET_LOCAL(simd1, WASM_SIMD_I32x4_ADD(WASM_GET_LOCAL(simd0),
WASM_GET_LOCAL(simd1))),
WASM_SIMD_CHECK_SPLAT4(I32x4, simd1, I32, expected),
WASM_RETURN1(WASM_ONE)));
FOR_INT32_INPUTS(i) { CHECK_EQ(1, r.Call(*i)); }
FOR_INT32_INPUTS(i) {
FOR_INT32_INPUTS(j) { CHECK_EQ(1, r.Call(*i, *j, *i + *j)); }
}
}
WASM_EXEC_TEST(I32x4Sub) {
FLAG_wasm_simd_prototype = true;
WasmRunner<int32_t> r(kExecuteCompiled, MachineType::Int32(),
MachineType::Int32(), MachineType::Int32());
byte a = 0;
byte b = 1;
byte expected = 2;
byte simd0 = r.AllocateLocal(kAstS128);
byte simd1 = r.AllocateLocal(kAstS128);
BUILD(r,
WASM_BLOCK(
WASM_SET_LOCAL(simd0, WASM_SIMD_I32x4_SPLAT(WASM_GET_LOCAL(a))),
WASM_SET_LOCAL(simd1, WASM_SIMD_I32x4_SPLAT(WASM_GET_LOCAL(b))),
WASM_SET_LOCAL(simd1, WASM_SIMD_I32x4_SUB(WASM_GET_LOCAL(simd0),
WASM_GET_LOCAL(simd1))),
WASM_SIMD_CHECK_SPLAT4(I32x4, simd1, I32, expected),
WASM_RETURN1(WASM_ONE)));
FOR_INT32_INPUTS(i) {
FOR_INT32_INPUTS(j) { CHECK_EQ(1, r.Call(*i, *j, *i - *j)); }
}
}
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