Commit 5354e28c authored by bbudge's avatar bbudge Committed by Commit bot

[Turbofan] Add native ARM support for Simd Float32x4 operations.

- Adds Float32x4 Abs, Neg, Equal, NotEqual.

LOG=N
BUG=v8:4124

Review-Url: https://codereview.chromium.org/2594683002
Cr-Commit-Position: refs/heads/master@{#41870}
parent 53fdf9d1
......@@ -1527,6 +1527,14 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
__ vcvt_f32_u32(i.OutputSimd128Register(), i.InputSimd128Register(0));
break;
}
case kArmFloat32x4Abs: {
__ vabs(i.OutputSimd128Register(), i.InputSimd128Register(0));
break;
}
case kArmFloat32x4Neg: {
__ vneg(i.OutputSimd128Register(), i.InputSimd128Register(0));
break;
}
case kArmFloat32x4Add: {
__ vadd(i.OutputSimd128Register(), i.InputSimd128Register(0),
i.InputSimd128Register(1));
......@@ -1537,6 +1545,17 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
i.InputSimd128Register(1));
break;
}
case kArmFloat32x4Eq: {
__ vceq(i.OutputSimd128Register(), i.InputSimd128Register(0),
i.InputSimd128Register(1));
break;
}
case kArmFloat32x4Ne: {
Simd128Register dst = i.OutputSimd128Register();
__ vceq(dst, i.InputSimd128Register(0), i.InputSimd128Register(1));
__ vmvn(dst, dst);
break;
}
case kArmInt32x4Splat: {
__ vdup(Neon32, i.OutputSimd128Register(), i.InputRegister(0));
break;
......
......@@ -125,8 +125,12 @@ namespace compiler {
V(ArmFloat32x4ReplaceLane) \
V(ArmFloat32x4FromInt32x4) \
V(ArmFloat32x4FromUint32x4) \
V(ArmFloat32x4Abs) \
V(ArmFloat32x4Neg) \
V(ArmFloat32x4Add) \
V(ArmFloat32x4Sub) \
V(ArmFloat32x4Eq) \
V(ArmFloat32x4Ne) \
V(ArmInt32x4Splat) \
V(ArmInt32x4ExtractLane) \
V(ArmInt32x4ReplaceLane) \
......
......@@ -113,8 +113,12 @@ int InstructionScheduler::GetTargetInstructionFlags(
case kArmFloat32x4ReplaceLane:
case kArmFloat32x4FromInt32x4:
case kArmFloat32x4FromUint32x4:
case kArmFloat32x4Abs:
case kArmFloat32x4Neg:
case kArmFloat32x4Add:
case kArmFloat32x4Sub:
case kArmFloat32x4Eq:
case kArmFloat32x4Ne:
case kArmInt32x4Splat:
case kArmInt32x4ExtractLane:
case kArmInt32x4ReplaceLane:
......
......@@ -2318,6 +2318,18 @@ void InstructionSelector::VisitFloat32x4FromUint32x4(Node* node) {
g.UseRegister(node->InputAt(0)));
}
void InstructionSelector::VisitFloat32x4Abs(Node* node) {
ArmOperandGenerator g(this);
Emit(kArmFloat32x4Abs, g.DefineAsRegister(node),
g.UseRegister(node->InputAt(0)));
}
void InstructionSelector::VisitFloat32x4Neg(Node* node) {
ArmOperandGenerator g(this);
Emit(kArmFloat32x4Neg, g.DefineAsRegister(node),
g.UseRegister(node->InputAt(0)));
}
void InstructionSelector::VisitFloat32x4Add(Node* node) {
ArmOperandGenerator g(this);
Emit(kArmFloat32x4Add, g.DefineAsRegister(node),
......@@ -2330,6 +2342,18 @@ void InstructionSelector::VisitFloat32x4Sub(Node* node) {
g.UseRegister(node->InputAt(0)), g.UseRegister(node->InputAt(1)));
}
void InstructionSelector::VisitFloat32x4Equal(Node* node) {
ArmOperandGenerator g(this);
Emit(kArmFloat32x4Eq, g.DefineAsRegister(node),
g.UseRegister(node->InputAt(0)), g.UseRegister(node->InputAt(1)));
}
void InstructionSelector::VisitFloat32x4NotEqual(Node* node) {
ArmOperandGenerator g(this);
Emit(kArmFloat32x4Ne, g.DefineAsRegister(node),
g.UseRegister(node->InputAt(0)), g.UseRegister(node->InputAt(1)));
}
void InstructionSelector::VisitCreateInt32x4(Node* node) {
ArmOperandGenerator g(this);
Emit(kArmInt32x4Splat, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
......
......@@ -1448,10 +1448,18 @@ void InstructionSelector::VisitNode(Node* node) {
return MarkAsSimd128(node), VisitFloat32x4FromInt32x4(node);
case IrOpcode::kFloat32x4FromUint32x4:
return MarkAsSimd128(node), VisitFloat32x4FromUint32x4(node);
case IrOpcode::kFloat32x4Abs:
return MarkAsSimd128(node), VisitFloat32x4Abs(node);
case IrOpcode::kFloat32x4Neg:
return MarkAsSimd128(node), VisitFloat32x4Neg(node);
case IrOpcode::kFloat32x4Add:
return MarkAsSimd128(node), VisitFloat32x4Add(node);
case IrOpcode::kFloat32x4Sub:
return MarkAsSimd128(node), VisitFloat32x4Sub(node);
case IrOpcode::kFloat32x4Equal:
return MarkAsSimd128(node), VisitFloat32x4Equal(node);
case IrOpcode::kFloat32x4NotEqual:
return MarkAsSimd128(node), VisitFloat32x4NotEqual(node);
case IrOpcode::kCreateInt32x4:
return MarkAsSimd128(node), VisitCreateInt32x4(node);
case IrOpcode::kInt32x4ExtractLane:
......@@ -1835,10 +1843,20 @@ void InstructionSelector::VisitFloat32x4FromUint32x4(Node* node) {
UNIMPLEMENTED();
}
void InstructionSelector::VisitFloat32x4Abs(Node* node) { UNIMPLEMENTED(); }
void InstructionSelector::VisitFloat32x4Neg(Node* node) { UNIMPLEMENTED(); }
void InstructionSelector::VisitFloat32x4Add(Node* node) { UNIMPLEMENTED(); }
void InstructionSelector::VisitFloat32x4Sub(Node* node) { UNIMPLEMENTED(); }
void InstructionSelector::VisitFloat32x4Equal(Node* node) { UNIMPLEMENTED(); }
void InstructionSelector::VisitFloat32x4NotEqual(Node* node) {
UNIMPLEMENTED();
}
void InstructionSelector::VisitInt32x4FromFloat32x4(Node* node) {
UNIMPLEMENTED();
}
......
......@@ -3244,12 +3244,22 @@ Node* WasmGraphBuilder::SimdOp(wasm::WasmOpcode opcode,
case wasm::kExprF32x4FromUint32x4:
return graph()->NewNode(jsgraph()->machine()->Float32x4FromUint32x4(),
inputs[0]);
case wasm::kExprF32x4Abs:
return graph()->NewNode(jsgraph()->machine()->Float32x4Abs(), inputs[0]);
case wasm::kExprF32x4Neg:
return graph()->NewNode(jsgraph()->machine()->Float32x4Neg(), inputs[0]);
case wasm::kExprF32x4Add:
return graph()->NewNode(jsgraph()->machine()->Float32x4Add(), inputs[0],
inputs[1]);
case wasm::kExprF32x4Sub:
return graph()->NewNode(jsgraph()->machine()->Float32x4Sub(), inputs[0],
inputs[1]);
case wasm::kExprF32x4Eq:
return graph()->NewNode(jsgraph()->machine()->Float32x4Equal(), inputs[0],
inputs[1]);
case wasm::kExprF32x4Ne:
return graph()->NewNode(jsgraph()->machine()->Float32x4NotEqual(),
inputs[0], inputs[1]);
case wasm::kExprI32x4Splat:
return graph()->NewNode(jsgraph()->machine()->CreateInt32x4(), inputs[0],
inputs[0], inputs[0], inputs[0]);
......
......@@ -460,6 +460,7 @@ class LocalDeclEncoder {
static_cast<byte>(index)
#define WASM_UNOP(opcode, x) x, static_cast<byte>(opcode)
#define WASM_BINOP(opcode, x, y) x, y, static_cast<byte>(opcode)
#define WASM_SIMD_UNOP(opcode, x) x, kSimdPrefix, static_cast<byte>(opcode)
#define WASM_SIMD_BINOP(opcode, x, y) \
x, y, kSimdPrefix, static_cast<byte>(opcode)
......
......@@ -15,9 +15,16 @@ using namespace v8::internal::wasm;
namespace {
typedef float (*FloatUnOp)(float);
typedef float (*FloatBinOp)(float, float);
typedef int32_t (*FloatCompareOp)(float, float);
typedef int32_t (*Int32BinOp)(int32_t, int32_t);
template <typename T>
T Negate(T a) {
return -a;
}
template <typename T>
T Add(T a, T b) {
return a + b;
......@@ -38,6 +45,12 @@ int32_t NotEqual(T a, T b) {
return a != b ? 0xFFFFFFFF : 0;
}
#if V8_TARGET_ARCH_ARM
int32_t Equal(float a, float b) { return a == b ? 0xFFFFFFFF : 0; }
int32_t NotEqual(float a, float b) { return a != b ? 0xFFFFFFFF : 0; }
#endif // V8_TARGET_ARCH_ARM
} // namespace
// TODO(gdeepti): These are tests using sample values to verify functional
......@@ -180,7 +193,29 @@ WASM_EXEC_TEST(S32x4Select) {
CHECK_EQ(1, r.Call(0x1234, 0x5678));
}
static void RunF32x4BinopTest(WasmOpcode simd_op, FloatBinOp expected_op) {
void RunF32x4UnOpTest(WasmOpcode simd_op, FloatUnOp expected_op) {
FLAG_wasm_simd_prototype = true;
WasmRunner<int32_t, float, float> r(kExecuteCompiled);
byte a = 0;
byte expected = 1;
byte simd = r.AllocateLocal(kAstS128);
BUILD(r, WASM_BLOCK(
WASM_SET_LOCAL(simd, WASM_SIMD_F32x4_SPLAT(WASM_GET_LOCAL(a))),
WASM_SET_LOCAL(
simd, WASM_SIMD_UNOP(simd_op & 0xffu, WASM_GET_LOCAL(simd))),
WASM_SIMD_CHECK_SPLAT4_F32(F32x4, simd, expected),
WASM_RETURN1(WASM_ONE)));
FOR_FLOAT32_INPUTS(i) {
if (std::isnan(*i)) continue;
CHECK_EQ(1, r.Call(*i, expected_op(*i)));
}
}
WASM_EXEC_TEST(F32x4Abs) { RunF32x4UnOpTest(kExprF32x4Abs, std::abs); }
WASM_EXEC_TEST(F32x4Neg) { RunF32x4UnOpTest(kExprF32x4Neg, Negate); }
void RunF32x4BinOpTest(WasmOpcode simd_op, FloatBinOp expected_op) {
FLAG_wasm_simd_prototype = true;
WasmRunner<int32_t, float, float, float> r(kExecuteCompiled);
byte a = 0;
......@@ -206,8 +241,37 @@ static void RunF32x4BinopTest(WasmOpcode simd_op, FloatBinOp expected_op) {
}
}
WASM_EXEC_TEST(F32x4Add) { RunF32x4BinopTest(kExprF32x4Add, Add); }
WASM_EXEC_TEST(F32x4Sub) { RunF32x4BinopTest(kExprF32x4Sub, Sub); }
WASM_EXEC_TEST(F32x4Add) { RunF32x4BinOpTest(kExprF32x4Add, Add); }
WASM_EXEC_TEST(F32x4Sub) { RunF32x4BinOpTest(kExprF32x4Sub, Sub); }
void RunF32x4CompareOpTest(WasmOpcode simd_op, FloatCompareOp expected_op) {
FLAG_wasm_simd_prototype = true;
WasmRunner<int32_t, float, float, int32_t> r(kExecuteCompiled);
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_F32x4_SPLAT(WASM_GET_LOCAL(a))),
WASM_SET_LOCAL(simd1, WASM_SIMD_F32x4_SPLAT(WASM_GET_LOCAL(b))),
WASM_SET_LOCAL(simd1, WASM_SIMD_BINOP(simd_op & 0xffu,
WASM_GET_LOCAL(simd0),
WASM_GET_LOCAL(simd1))),
WASM_SIMD_CHECK_SPLAT4(I32x4, simd1, I32, expected),
WASM_RETURN1(WASM_ONE)));
FOR_FLOAT32_INPUTS(i) {
if (std::isnan(*i)) continue;
FOR_FLOAT32_INPUTS(j) {
if (std::isnan(*j)) continue;
CHECK_EQ(1, r.Call(*i, *j, expected_op(*i, *j)));
}
}
}
WASM_EXEC_TEST(F32x4Equal) { RunF32x4CompareOpTest(kExprF32x4Eq, Equal); }
WASM_EXEC_TEST(F32x4NotEqual) { RunF32x4CompareOpTest(kExprF32x4Ne, NotEqual); }
#endif // V8_TARGET_ARCH_ARM
WASM_EXEC_TEST(I32x4Splat) {
......@@ -337,7 +401,7 @@ WASM_EXEC_TEST(I32x4FromFloat32x4) {
}
#endif // V8_TARGET_ARCH_ARM
static void RunI32x4BinopTest(WasmOpcode simd_op, Int32BinOp expected_op) {
void RunI32x4BinOpTest(WasmOpcode simd_op, Int32BinOp expected_op) {
FLAG_wasm_simd_prototype = true;
WasmRunner<int32_t, int32_t, int32_t, int32_t> r(kExecuteCompiled);
byte a = 0;
......@@ -359,12 +423,12 @@ static void RunI32x4BinopTest(WasmOpcode simd_op, Int32BinOp expected_op) {
}
}
WASM_EXEC_TEST(I32x4Add) { RunI32x4BinopTest(kExprI32x4Add, Add); }
WASM_EXEC_TEST(I32x4Add) { RunI32x4BinOpTest(kExprI32x4Add, Add); }
WASM_EXEC_TEST(I32x4Sub) { RunI32x4BinopTest(kExprI32x4Sub, Sub); }
WASM_EXEC_TEST(I32x4Sub) { RunI32x4BinOpTest(kExprI32x4Sub, Sub); }
#if V8_TARGET_ARCH_ARM
WASM_EXEC_TEST(I32x4Equal) { RunI32x4BinopTest(kExprI32x4Eq, Equal); }
WASM_EXEC_TEST(I32x4Equal) { RunI32x4BinOpTest(kExprI32x4Eq, Equal); }
WASM_EXEC_TEST(I32x4NotEqual) { RunI32x4BinopTest(kExprI32x4Ne, NotEqual); }
WASM_EXEC_TEST(I32x4NotEqual) { RunI32x4BinOpTest(kExprI32x4Ne, NotEqual); }
#endif // V8_TARGET_ARCH_ARM
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