Commit 8b130a84 authored by aseemgarg's avatar aseemgarg Committed by Commit bot

[wasm] Implement simd lowering for F32x4 and I32x4 compare ops

R=bbudge@chromium.org,titzer@chromium.org,gdeepti@chromium.org,bradnelson@chromium.org,mtrofin@chromium.org
BUG=v8:6020

Review-Url: https://codereview.chromium.org/2728823005
Cr-Commit-Position: refs/heads/master@{#43562}
parent 81ad6b52
......@@ -100,6 +100,26 @@ void SimdScalarLowering::LowerGraph() {
V(Float32x4FromInt32x4) \
V(Float32x4FromUint32x4)
#define FOREACH_FLOAT32X4_TO_SIMD1X4OPCODE(V) \
V(Float32x4Equal) \
V(Float32x4NotEqual) \
V(Float32x4LessThan) \
V(Float32x4LessThanOrEqual) \
V(Float32x4GreaterThan) \
V(Float32x4GreaterThanOrEqual)
#define FOREACH_INT32X4_TO_SIMD1X4OPCODE(V) \
V(Int32x4Equal) \
V(Int32x4NotEqual) \
V(Int32x4LessThan) \
V(Int32x4LessThanOrEqual) \
V(Int32x4GreaterThan) \
V(Int32x4GreaterThanOrEqual) \
V(Uint32x4LessThan) \
V(Uint32x4LessThanOrEqual) \
V(Uint32x4GreaterThan) \
V(Uint32x4GreaterThanOrEqual)
void SimdScalarLowering::SetLoweredType(Node* node, Node* output) {
switch (node->opcode()) {
#define CASE_STMT(name) case IrOpcode::k##name:
......@@ -114,24 +134,35 @@ void SimdScalarLowering::SetLoweredType(Node* node, Node* output) {
replacements_[node->id()].type = SimdType::kFloat32;
break;
}
#undef CASE_STMT
FOREACH_FLOAT32X4_TO_SIMD1X4OPCODE(CASE_STMT)
FOREACH_INT32X4_TO_SIMD1X4OPCODE(CASE_STMT) {
replacements_[node->id()].type = SimdType::kSimd1x4;
break;
}
default: {
switch (output->opcode()) {
FOREACH_FLOAT32X4_TO_SIMD1X4OPCODE(CASE_STMT)
case IrOpcode::kFloat32x4FromInt32x4:
case IrOpcode::kFloat32x4FromUint32x4: {
replacements_[node->id()].type = SimdType::kInt32;
break;
}
FOREACH_INT32X4_TO_SIMD1X4OPCODE(CASE_STMT)
case IrOpcode::kInt32x4FromFloat32x4:
case IrOpcode::kUint32x4FromFloat32x4: {
replacements_[node->id()].type = SimdType::kFloat32;
break;
}
case IrOpcode::kSimd32x4Select: {
replacements_[node->id()].type = SimdType::kSimd1x4;
break;
}
default: {
replacements_[node->id()].type = replacements_[output->id()].type;
}
}
}
#undef CASE_STMT
}
}
......@@ -252,13 +283,17 @@ void SimdScalarLowering::LowerStoreOp(MachineRepresentation rep, Node* node,
}
void SimdScalarLowering::LowerBinaryOp(Node* node, SimdType input_rep_type,
const Operator* op) {
const Operator* op, bool invert_inputs) {
DCHECK(node->InputCount() == 2);
Node** rep_left = GetReplacementsWithType(node->InputAt(0), input_rep_type);
Node** rep_right = GetReplacementsWithType(node->InputAt(1), input_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]);
if (invert_inputs) {
rep_node[i] = graph()->NewNode(op, rep_right[i], rep_left[i]);
} else {
rep_node[i] = graph()->NewNode(op, rep_left[i], rep_right[i]);
}
}
ReplaceNode(node, rep_node);
}
......@@ -372,6 +407,21 @@ void SimdScalarLowering::LowerShiftOp(Node* node, const Operator* op) {
ReplaceNode(node, rep_node);
}
void SimdScalarLowering::LowerNotEqual(Node* node, SimdType input_rep_type,
const Operator* op) {
DCHECK(node->InputCount() == 2);
Node** rep_left = GetReplacementsWithType(node->InputAt(0), input_rep_type);
Node** rep_right = GetReplacementsWithType(node->InputAt(1), input_rep_type);
Node* rep_node[kMaxLanes];
for (int i = 0; i < kMaxLanes; ++i) {
Diamond d(graph(), common(),
graph()->NewNode(op, rep_left[i], rep_right[i]));
rep_node[i] = d.Phi(MachineRepresentation::kWord32,
jsgraph_->Int32Constant(0), jsgraph_->Int32Constant(1));
}
ReplaceNode(node, rep_node);
}
void SimdScalarLowering::LowerNode(Node* node) {
SimdType rep_type = ReplacementType(node);
switch (node->opcode()) {
......@@ -654,6 +704,64 @@ void SimdScalarLowering::LowerNode(Node* node) {
ReplaceNode(node, rep_node);
break;
}
#define COMPARISON_CASE(type, simd_op, lowering_op, invert) \
case IrOpcode::simd_op: { \
LowerBinaryOp(node, SimdType::k##type, machine()->lowering_op(), invert); \
break; \
}
COMPARISON_CASE(Float32, kFloat32x4Equal, Float32Equal, false)
COMPARISON_CASE(Float32, kFloat32x4LessThan, Float32LessThan, false)
COMPARISON_CASE(Float32, kFloat32x4LessThanOrEqual,
Float32LessThanOrEqual, false)
COMPARISON_CASE(Float32, kFloat32x4GreaterThan, Float32LessThan, true)
COMPARISON_CASE(Float32, kFloat32x4GreaterThanOrEqual,
Float32LessThanOrEqual, true)
COMPARISON_CASE(Int32, kInt32x4Equal, Word32Equal, false)
COMPARISON_CASE(Int32, kInt32x4LessThan, Int32LessThan, false)
COMPARISON_CASE(Int32, kInt32x4LessThanOrEqual, Int32LessThanOrEqual,
false)
COMPARISON_CASE(Int32, kInt32x4GreaterThan, Int32LessThan, true)
COMPARISON_CASE(Int32, kInt32x4GreaterThanOrEqual, Int32LessThanOrEqual,
true)
COMPARISON_CASE(Int32, kUint32x4LessThan, Uint32LessThan, false)
COMPARISON_CASE(Int32, kUint32x4LessThanOrEqual, Uint32LessThanOrEqual,
false)
COMPARISON_CASE(Int32, kUint32x4GreaterThan, Uint32LessThan, true)
COMPARISON_CASE(Int32, kUint32x4GreaterThanOrEqual, Uint32LessThanOrEqual,
true)
#undef COMPARISON_CASE
case IrOpcode::kFloat32x4NotEqual: {
LowerNotEqual(node, SimdType::kFloat32, machine()->Float32Equal());
break;
}
case IrOpcode::kInt32x4NotEqual: {
LowerNotEqual(node, SimdType::kInt32, machine()->Word32Equal());
break;
}
case IrOpcode::kSimd32x4Select: {
DCHECK(node->InputCount() == 3);
DCHECK(ReplacementType(node->InputAt(0)) == SimdType::kSimd1x4);
Node** boolean_input = GetReplacements(node->InputAt(0));
Node** rep_left = GetReplacementsWithType(node->InputAt(1), rep_type);
Node** rep_right = GetReplacementsWithType(node->InputAt(2), rep_type);
Node* rep_node[kMaxLanes];
for (int i = 0; i < kMaxLanes; ++i) {
Diamond d(graph(), common(),
graph()->NewNode(machine()->Word32Equal(), boolean_input[i],
jsgraph_->Int32Constant(0)));
if (rep_type == SimdType::kFloat32) {
rep_node[i] =
d.Phi(MachineRepresentation::kFloat32, rep_right[1], rep_left[0]);
} else if (rep_type == SimdType::kInt32) {
rep_node[i] =
d.Phi(MachineRepresentation::kWord32, rep_right[1], rep_left[0]);
} else {
UNREACHABLE();
}
}
ReplaceNode(node, rep_node);
break;
}
default: { DefaultLowering(node); }
}
}
......@@ -715,7 +823,8 @@ Node** SimdScalarLowering::GetReplacementsWithType(Node* node, SimdType type) {
result[i] = nullptr;
}
}
} else {
} else if (ReplacementType(node) == SimdType::kFloat32 &&
type == SimdType::kInt32) {
for (int i = 0; i < kMaxLanes; ++i) {
if (replacements[i] != nullptr) {
result[i] = graph()->NewNode(machine()->BitcastFloat32ToInt32(),
......@@ -724,6 +833,8 @@ Node** SimdScalarLowering::GetReplacementsWithType(Node* node, SimdType type) {
result[i] = nullptr;
}
}
} else {
UNREACHABLE();
}
return result;
}
......
......@@ -28,7 +28,7 @@ class SimdScalarLowering {
private:
enum class State : uint8_t { kUnvisited, kOnStack, kVisited };
enum class SimdType : uint8_t { kInt32, kFloat32 };
enum class SimdType : uint8_t { kInt32, kFloat32, kSimd1x4 };
static const int kMaxLanes = 4;
static const int kLaneWidth = 16 / kMaxLanes;
......@@ -64,12 +64,14 @@ class SimdScalarLowering {
const Operator* load_op);
void LowerStoreOp(MachineRepresentation rep, Node* node,
const Operator* store_op, SimdType rep_type);
void LowerBinaryOp(Node* node, SimdType input_rep_type, const Operator* op);
void LowerBinaryOp(Node* node, SimdType input_rep_type, const Operator* op,
bool invert_inputs = false);
void LowerUnaryOp(Node* node, SimdType input_rep_type, const Operator* op);
void LowerIntMinMax(Node* node, const Operator* op, bool is_max);
void LowerConvertFromFloat(Node* node, bool is_signed);
void LowerShiftOp(Node* node, const Operator* op);
Node* BuildF64Trunc(Node* input);
void LowerNotEqual(Node* node, SimdType input_rep_type, const Operator* op);
JSGraph* const jsgraph_;
NodeMarker<State> state_;
......
......@@ -3408,6 +3408,21 @@ Node* WasmGraphBuilder::SimdOp(wasm::WasmOpcode opcode,
case wasm::kExprF32x4Ne:
return graph()->NewNode(jsgraph()->machine()->Float32x4NotEqual(),
inputs[0], inputs[1]);
// TODO(aseemgarg): Get rid of GreaterThan and GreaterThanEquals machine ops
// for all SIMD types.
case wasm::kExprF32x4Gt:
return graph()->NewNode(jsgraph()->machine()->Float32x4GreaterThan(),
inputs[0], inputs[1]);
case wasm::kExprF32x4Ge:
return graph()->NewNode(
jsgraph()->machine()->Float32x4GreaterThanOrEqual(), inputs[0],
inputs[1]);
case wasm::kExprF32x4Lt:
return graph()->NewNode(jsgraph()->machine()->Float32x4LessThan(),
inputs[0], inputs[1]);
case wasm::kExprF32x4Le:
return graph()->NewNode(jsgraph()->machine()->Float32x4LessThanOrEqual(),
inputs[0], inputs[1]);
case wasm::kExprI32x4Splat:
return graph()->NewNode(jsgraph()->machine()->Int32x4Splat(), inputs[0]);
case wasm::kExprI32x4SConvertF32x4:
......
......@@ -28,12 +28,27 @@ typedef int8_t (*Int8UnOp)(int8_t);
typedef int8_t (*Int8BinOp)(int8_t, int8_t);
typedef int8_t (*Int8ShiftOp)(int8_t, int);
#if V8_TARGET_ARCH_ARM
// Floating point specific value functions, only used by ARM so far.
#if !V8_TARGET_ARCH_ARM && !V8_TARGET_ARCH_X64
#define SIMD_LOWERING_TARGET 1
#else
#define SIMD_LOWERING_TARGET 0
#endif // !V8_TARGET_ARCH_ARM && !V8_TARGET_ARCH_X64
#if V8_TARGET_ARCH_ARM || SIMD_LOWERING_TARGET
int32_t Equal(float a, float b) { return a == b ? 1 : 0; }
int32_t NotEqual(float a, float b) { return a != b ? 1 : 0; }
#endif // V8_TARGET_ARCH_ARM
#endif // V8_TARGET_ARCH_ARM || SIMD_LOWERING_TARGET
#if SIMD_LOWERING_TARGET
int32_t Less(float a, float b) { return a < b ? 1 : 0; }
int32_t LessEqual(float a, float b) { return a <= b ? 1 : 0; }
int32_t Greater(float a, float b) { return a > b ? 1 : 0; }
int32_t GreaterEqual(float a, float b) { return a >= b ? 1 : 0; }
#endif // SIMD_LOWERING_TARGET
// Generic expected value functions.
template <typename T>
......@@ -224,12 +239,6 @@ T Sqrt(T a) {
} // namespace
#if !V8_TARGET_ARCH_ARM && !V8_TARGET_ARCH_X64
#define SIMD_LOWERING_TARGET 1
#else
#define SIMD_LOWERING_TARGET 0
#endif // !V8_TARGET_ARCH_ARM && !V8_TARGET_ARCH_X64
#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( \
......@@ -492,7 +501,7 @@ WASM_EXEC_COMPILED_TEST(Simd_F32x4_Max) {
}
#endif // SIMD_LOWERING_TARGET
#if V8_TARGET_ARCH_ARM
#if V8_TARGET_ARCH_ARM || SIMD_LOWERING_TARGET
void RunF32x4CompareOpTest(WasmOpcode simd_op, FloatCompareOp expected_op) {
FLAG_wasm_simd_prototype = true;
WasmRunner<int32_t, float, float, int32_t> r(kExecuteCompiled);
......@@ -527,7 +536,22 @@ WASM_EXEC_COMPILED_TEST(F32x4Equal) {
WASM_EXEC_COMPILED_TEST(F32x4NotEqual) {
RunF32x4CompareOpTest(kExprF32x4Ne, NotEqual);
}
#endif // V8_TARGET_ARCH_ARM
#endif // V8_TARGET_ARCH_ARM || SIMD_LOWERING_TARGET
#if SIMD_LOWERING_TARGET
WASM_EXEC_COMPILED_TEST(F32x4LessThan) {
RunF32x4CompareOpTest(kExprF32x4Lt, Less);
}
WASM_EXEC_COMPILED_TEST(F32x4LessThanOrEqual) {
RunF32x4CompareOpTest(kExprF32x4Le, LessEqual);
}
WASM_EXEC_COMPILED_TEST(F32x4GreaterThan) {
RunF32x4CompareOpTest(kExprF32x4Gt, Greater);
}
WASM_EXEC_COMPILED_TEST(F32x4GreaterThanOrEqual) {
RunF32x4CompareOpTest(kExprF32x4Ge, GreaterEqual);
}
#endif // SIMD_LOWERING_TARGET
WASM_EXEC_COMPILED_TEST(I32x4Splat) {
FLAG_wasm_simd_prototype = true;
......@@ -894,9 +918,7 @@ WASM_EXEC_COMPILED_TEST(Ui32x4Min) {
WASM_EXEC_COMPILED_TEST(Ui32x4Max) {
RunI32x4BinOpTest(kExprI32x4MaxU, UnsignedMaximum);
}
#endif // V8_TARGET_ARCH_ARM || SIMD_LOWERING_TARGET
#if V8_TARGET_ARCH_ARM
void RunI32x4CompareOpTest(WasmOpcode simd_op, Int32BinOp expected_op) {
FLAG_wasm_simd_prototype = true;
WasmRunner<int32_t, int32_t, int32_t, int32_t> r(kExecuteCompiled);
......@@ -957,9 +979,7 @@ WASM_EXEC_COMPILED_TEST(Ui32x4Less) {
WASM_EXEC_COMPILED_TEST(Ui32x4LessEqual) {
RunI32x4CompareOpTest(kExprI32x4LeU, UnsignedLessEqual);
}
#endif // V8_TARGET_ARCH_ARM
#if V8_TARGET_ARCH_ARM || SIMD_LOWERING_TARGET
void RunI32x4ShiftOpTest(WasmOpcode simd_op, Int32ShiftOp expected_op,
int shift) {
FLAG_wasm_simd_prototype = true;
......
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