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

[wasm]implement simd lowering for f32x4->i32x4, i32x4 min/max and shift instructions

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

Review-Url: https://codereview.chromium.org/2718323003
Cr-Commit-Position: refs/heads/master@{#43510}
parent a727f9e8
......@@ -80,9 +80,15 @@ void SimdScalarLowering::LowerGraph() {
V(Int32x4Add) \
V(Int32x4Sub) \
V(Int32x4Mul) \
V(Int32x4Min) \
V(Int32x4Max) \
V(Uint32x4Min) \
V(Uint32x4Max) \
V(Simd128And) \
V(Simd128Or) \
V(Simd128Xor)
V(Simd128Xor) \
V(Int32x4FromFloat32x4) \
V(Uint32x4FromFloat32x4)
#define FOREACH_FLOAT32X4_OPCODE(V) \
V(Float32x4Splat) \
......@@ -115,11 +121,20 @@ void SimdScalarLowering::SetLoweredType(Node* node, Node* output) {
}
#undef CASE_STMT
default: {
if (output->opcode() == IrOpcode::kFloat32x4FromInt32x4 ||
output->opcode() == IrOpcode::kFloat32x4FromUint32x4) {
replacements_[node->id()].type = SimdType::kInt32;
} else {
replacements_[node->id()].type = replacements_[output->id()].type;
switch (output->opcode()) {
case IrOpcode::kFloat32x4FromInt32x4:
case IrOpcode::kFloat32x4FromUint32x4: {
replacements_[node->id()].type = SimdType::kInt32;
break;
}
case IrOpcode::kInt32x4FromFloat32x4:
case IrOpcode::kUint32x4FromFloat32x4: {
replacements_[node->id()].type = SimdType::kFloat32;
break;
}
default: {
replacements_[node->id()].type = replacements_[output->id()].type;
}
}
}
}
......@@ -264,6 +279,75 @@ void SimdScalarLowering::LowerUnaryOp(Node* node, SimdType input_rep_type,
ReplaceNode(node, rep_node);
}
void SimdScalarLowering::LowerIntMinMax(Node* node, const Operator* op,
bool is_max) {
DCHECK(node->InputCount() == 2);
Node** rep_left = GetReplacementsWithType(node->InputAt(0), SimdType::kInt32);
Node** rep_right =
GetReplacementsWithType(node->InputAt(1), SimdType::kInt32);
Node* rep_node[kMaxLanes];
for (int i = 0; i < kMaxLanes; ++i) {
Diamond d(graph(), common(),
graph()->NewNode(op, rep_left[i], rep_right[i]));
if (is_max) {
rep_node[i] =
d.Phi(MachineRepresentation::kWord32, rep_right[i], rep_left[i]);
} else {
rep_node[i] =
d.Phi(MachineRepresentation::kWord32, rep_left[i], rep_right[i]);
}
}
ReplaceNode(node, rep_node);
}
void SimdScalarLowering::LowerConvertFromFloat(Node* node, bool is_signed) {
DCHECK(node->InputCount() == 1);
Node** rep = GetReplacementsWithType(node->InputAt(0), SimdType::kFloat32);
Node* rep_node[kMaxLanes];
Node* double_zero = graph()->NewNode(common()->Float64Constant(0.0));
Node* min = graph()->NewNode(
common()->Float64Constant(static_cast<double>(is_signed ? kMinInt : 0)));
Node* max = graph()->NewNode(common()->Float64Constant(
static_cast<double>(is_signed ? kMaxInt : 0xffffffffu)));
for (int i = 0; i < kMaxLanes; ++i) {
Node* double_rep =
graph()->NewNode(machine()->ChangeFloat32ToFloat64(), rep[i]);
Diamond nan_d(graph(), common(), graph()->NewNode(machine()->Float64Equal(),
double_rep, double_rep));
Node* temp =
nan_d.Phi(MachineRepresentation::kFloat64, double_rep, double_zero);
Diamond min_d(graph(), common(),
graph()->NewNode(machine()->Float64LessThan(), temp, min));
temp = min_d.Phi(MachineRepresentation::kFloat64, min, temp);
Diamond max_d(graph(), common(),
graph()->NewNode(machine()->Float64LessThan(), max, temp));
temp = max_d.Phi(MachineRepresentation::kFloat64, max, temp);
Node* trunc =
graph()->NewNode(machine()->Float64RoundTruncate().op(), temp);
if (is_signed) {
rep_node[i] = graph()->NewNode(machine()->ChangeFloat64ToInt32(), trunc);
} else {
rep_node[i] =
graph()->NewNode(machine()->TruncateFloat64ToUint32(), trunc);
}
}
ReplaceNode(node, rep_node);
}
void SimdScalarLowering::LowerShiftOp(Node* node, const Operator* op) {
static int32_t shift_mask = 0x1f;
DCHECK_EQ(1, node->InputCount());
int32_t shift_amount = OpParameter<int32_t>(node);
Node* shift_node =
graph()->NewNode(common()->Int32Constant(shift_amount & shift_mask));
Node** rep = GetReplacementsWithType(node->InputAt(0), SimdType::kInt32);
Node* rep_node[kMaxLanes];
for (int i = 0; i < kMaxLanes; ++i) {
rep_node[i] = graph()->NewNode(op, rep[i], shift_node);
}
ReplaceNode(node, rep_node);
}
void SimdScalarLowering::LowerNode(Node* node) {
SimdType rep_type = ReplacementType(node);
switch (node->opcode()) {
......@@ -422,6 +506,22 @@ void SimdScalarLowering::LowerNode(Node* node) {
I32X4_BINOP_CASE(kSimd128Or, Word32Or)
I32X4_BINOP_CASE(kSimd128Xor, Word32Xor)
#undef I32X4_BINOP_CASE
case IrOpcode::kInt32x4Max: {
LowerIntMinMax(node, machine()->Int32LessThan(), true);
break;
}
case IrOpcode::kInt32x4Min: {
LowerIntMinMax(node, machine()->Int32LessThan(), false);
break;
}
case IrOpcode::kUint32x4Max: {
LowerIntMinMax(node, machine()->Uint32LessThan(), true);
break;
}
case IrOpcode::kUint32x4Min: {
LowerIntMinMax(node, machine()->Uint32LessThan(), false);
break;
}
case IrOpcode::kInt32x4Neg: {
DCHECK(node->InputCount() == 1);
Node** rep = GetReplacementsWithType(node->InputAt(0), rep_type);
......@@ -444,6 +544,26 @@ void SimdScalarLowering::LowerNode(Node* node) {
ReplaceNode(node, rep_node);
break;
}
case IrOpcode::kInt32x4FromFloat32x4: {
LowerConvertFromFloat(node, true);
break;
}
case IrOpcode::kUint32x4FromFloat32x4: {
LowerConvertFromFloat(node, false);
break;
}
case IrOpcode::kInt32x4ShiftLeftByScalar: {
LowerShiftOp(node, machine()->Word32Shl());
break;
}
case IrOpcode::kInt32x4ShiftRightByScalar: {
LowerShiftOp(node, machine()->Word32Sar());
break;
}
case IrOpcode::kUint32x4ShiftRightByScalar: {
LowerShiftOp(node, machine()->Word32Shr());
break;
}
#define F32X4_BINOP_CASE(name) \
case IrOpcode::kFloat32x4##name: { \
LowerBinaryOp(node, rep_type, machine()->Float32##name()); \
......
......@@ -61,6 +61,9 @@ class SimdScalarLowering {
const Operator* store_op, SimdType rep_type);
void LowerBinaryOp(Node* node, SimdType input_rep_type, const Operator* op);
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);
struct NodeState {
Node* node;
......
......@@ -752,7 +752,9 @@ WASM_EXEC_COMPILED_TEST(I8x16ReplaceLane) {
CHECK_EQ(1, r.Call(1, 2));
}
#endif // V8_TARGET_ARCH_ARM
#if V8_TARGET_ARCH_ARM || SIMD_LOWERING_TARGET
// Determines if conversion from float to int will be valid.
bool CanRoundToZeroAndConvert(double val, bool unsigned_integer) {
const double max_uint = static_cast<double>(0xffffffffu);
......@@ -816,9 +818,7 @@ WASM_EXEC_COMPILED_TEST(I32x4FromFloat32x4) {
CHECK_EQ(1, r.Call(*i, signed_value, unsigned_value));
}
}
#endif // V8_TARGET_ARCH_ARM
#if V8_TARGET_ARCH_ARM || SIMD_LOWERING_TARGET
void RunI32x4UnOpTest(WasmOpcode simd_op, Int32UnOp expected_op) {
FLAG_wasm_simd_prototype = true;
WasmRunner<int32_t, int32_t, int32_t> r(kExecuteCompiled);
......@@ -868,9 +868,7 @@ WASM_EXEC_COMPILED_TEST(S128And) { RunI32x4BinOpTest(kExprS128And, And); }
WASM_EXEC_COMPILED_TEST(S128Or) { RunI32x4BinOpTest(kExprS128Or, Or); }
WASM_EXEC_COMPILED_TEST(S128Xor) { RunI32x4BinOpTest(kExprS128Xor, Xor); }
#endif // V8_TARGET_ARCH_ARM || SIMD_LOWERING_TARGET
#if V8_TARGET_ARCH_ARM
WASM_EXEC_COMPILED_TEST(I32x4Min) {
RunI32x4BinOpTest(kExprI32x4MinS, Minimum);
}
......@@ -886,9 +884,9 @@ 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);
......@@ -949,7 +947,9 @@ 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;
......@@ -976,6 +976,9 @@ WASM_EXEC_COMPILED_TEST(I32x4ShrS) {
WASM_EXEC_COMPILED_TEST(I32x4ShrU) {
RunI32x4ShiftOpTest(kExprI32x4ShrU, LogicalShiftRight, 1);
}
#endif // V8_TARGET_ARCH_ARM || SIMD_LOWERING_TARGET
#if V8_TARGET_ARCH_ARM
void RunI16x8UnOpTest(WasmOpcode simd_op, Int16UnOp expected_op) {
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