Commit 2f80165f authored by jacob.bramley's avatar jacob.bramley Committed by Commit bot

[arm64] Implement Float(32|64)(Min|Max) using fcsel.

Float(32|64)Min:
  // (a < b) ? a : b
  fcmp da, db
  fcsel dd, da, db, lo

Float(32|64)Max:
  // (b < a) ? a : b
  fcmp db, da
  fcsel dd, da, db, lo

BUG=

Review URL: https://codereview.chromium.org/1360603003

Cr-Commit-Position: refs/heads/master@{#31621}
parent 95e26ec4
......@@ -822,12 +822,16 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
i.InputFloat32Register(1));
break;
case kArm64Float32Max:
__ Fmax(i.OutputFloat32Register(), i.InputFloat32Register(0),
i.InputFloat32Register(1));
// (b < a) ? a : b
__ Fcmp(i.InputFloat32Register(1), i.InputFloat32Register(0));
__ Fcsel(i.OutputFloat32Register(), i.InputFloat32Register(0),
i.InputFloat32Register(1), lo);
break;
case kArm64Float32Min:
__ Fmin(i.OutputFloat32Register(), i.InputFloat32Register(0),
i.InputFloat32Register(1));
// (a < b) ? a : b
__ Fcmp(i.InputFloat32Register(0), i.InputFloat32Register(1));
__ Fcsel(i.OutputFloat32Register(), i.InputFloat32Register(0),
i.InputFloat32Register(1), lo);
break;
case kArm64Float32Abs:
__ Fabs(i.OutputFloat32Register(), i.InputFloat32Register(0));
......@@ -873,12 +877,16 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
break;
}
case kArm64Float64Max:
__ Fmax(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
i.InputDoubleRegister(1));
// (b < a) ? a : b
__ Fcmp(i.InputDoubleRegister(1), i.InputDoubleRegister(0));
__ Fcsel(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
i.InputDoubleRegister(1), lo);
break;
case kArm64Float64Min:
__ Fmin(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
i.InputDoubleRegister(1));
// (a < b) ? a : b
__ Fcmp(i.InputDoubleRegister(0), i.InputDoubleRegister(1));
__ Fcsel(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
i.InputDoubleRegister(1), lo);
break;
case kArm64Float64Abs:
__ Fabs(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
......
......@@ -1369,16 +1369,24 @@ void InstructionSelector::VisitFloat64Mod(Node* node) {
}
void InstructionSelector::VisitFloat32Max(Node* node) { UNREACHABLE(); }
void InstructionSelector::VisitFloat32Max(Node* node) {
VisitRRR(this, kArm64Float32Max, node);
}
void InstructionSelector::VisitFloat64Max(Node* node) { UNREACHABLE(); }
void InstructionSelector::VisitFloat64Max(Node* node) {
VisitRRR(this, kArm64Float64Max, node);
}
void InstructionSelector::VisitFloat32Min(Node* node) { UNREACHABLE(); }
void InstructionSelector::VisitFloat32Min(Node* node) {
VisitRRR(this, kArm64Float32Min, node);
}
void InstructionSelector::VisitFloat64Min(Node* node) { UNREACHABLE(); }
void InstructionSelector::VisitFloat64Min(Node* node) {
VisitRRR(this, kArm64Float64Min, node);
}
void InstructionSelector::VisitFloat32Abs(Node* node) {
......@@ -1958,7 +1966,11 @@ void InstructionSelector::VisitFloat64InsertHighWord32(Node* node) {
// static
MachineOperatorBuilder::Flags
InstructionSelector::SupportedMachineOperatorFlags() {
return MachineOperatorBuilder::kFloat64RoundDown |
return MachineOperatorBuilder::kFloat32Max |
MachineOperatorBuilder::kFloat32Min |
MachineOperatorBuilder::kFloat64Max |
MachineOperatorBuilder::kFloat64Min |
MachineOperatorBuilder::kFloat64RoundDown |
MachineOperatorBuilder::kFloat64RoundTruncate |
MachineOperatorBuilder::kFloat64RoundTiesAway |
MachineOperatorBuilder::kWord32ShiftIsSafe |
......
......@@ -105,7 +105,7 @@ class MachineOperatorBuilder final : public ZoneObject {
// for operations that are unsupported by some back-ends.
enum Flag {
kNoFlags = 0u,
// Note that Float*Max behaves like `(a < b) ? b : a`, not like Math.max().
// Note that Float*Max behaves like `(b < a) ? a : b`, not like Math.max().
// Note that Float*Min behaves like `(a < b) ? a : b`, not like Math.min().
kFloat32Max = 1u << 0,
kFloat32Min = 1u << 1,
......
......@@ -355,6 +355,12 @@ class RawMachineAssembler {
Node* Float32Div(Node* a, Node* b) {
return AddNode(machine()->Float32Div(), a, b);
}
Node* Float32Max(Node* a, Node* b) {
return AddNode(machine()->Float32Max().op(), a, b);
}
Node* Float32Min(Node* a, Node* b) {
return AddNode(machine()->Float32Min().op(), a, b);
}
Node* Float32Abs(Node* a) { return AddNode(machine()->Float32Abs(), a); }
Node* Float32Sqrt(Node* a) { return AddNode(machine()->Float32Sqrt(), a); }
Node* Float32Equal(Node* a, Node* b) {
......@@ -389,6 +395,12 @@ class RawMachineAssembler {
Node* Float64Mod(Node* a, Node* b) {
return AddNode(machine()->Float64Mod(), a, b);
}
Node* Float64Max(Node* a, Node* b) {
return AddNode(machine()->Float64Max().op(), a, b);
}
Node* Float64Min(Node* a, Node* b) {
return AddNode(machine()->Float64Min().op(), a, b);
}
Node* Float64Abs(Node* a) { return AddNode(machine()->Float64Abs(), a); }
Node* Float64Sqrt(Node* a) { return AddNode(machine()->Float64Sqrt(), a); }
Node* Float64Equal(Node* a, Node* b) {
......
......@@ -3114,6 +3114,78 @@ TEST_F(InstructionSelectorTest, Float64SubWithMinusZero) {
EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
}
TEST_F(InstructionSelectorTest, Float32Max) {
StreamBuilder m(this, kMachFloat32, kMachFloat32, kMachFloat32);
Node* const p0 = m.Parameter(0);
Node* const p1 = m.Parameter(1);
Node* const n = m.Float32Max(p0, p1);
m.Return(n);
Stream s = m.Build();
// Float32Max is `(b < a) ? a : b`.
ASSERT_EQ(1U, s.size());
EXPECT_EQ(kArm64Float32Max, s[0]->arch_opcode());
ASSERT_EQ(2U, s[0]->InputCount());
EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
ASSERT_EQ(1U, s[0]->OutputCount());
EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
}
TEST_F(InstructionSelectorTest, Float32Min) {
StreamBuilder m(this, kMachFloat32, kMachFloat32, kMachFloat32);
Node* const p0 = m.Parameter(0);
Node* const p1 = m.Parameter(1);
Node* const n = m.Float32Min(p0, p1);
m.Return(n);
Stream s = m.Build();
// Float32Min is `(a < b) ? a : b`.
ASSERT_EQ(1U, s.size());
EXPECT_EQ(kArm64Float32Min, s[0]->arch_opcode());
ASSERT_EQ(2U, s[0]->InputCount());
EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
ASSERT_EQ(1U, s[0]->OutputCount());
EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
}
TEST_F(InstructionSelectorTest, Float64Max) {
StreamBuilder m(this, kMachFloat64, kMachFloat64, kMachFloat64);
Node* const p0 = m.Parameter(0);
Node* const p1 = m.Parameter(1);
Node* const n = m.Float64Max(p0, p1);
m.Return(n);
Stream s = m.Build();
// Float64Max is `(b < a) ? a : b`.
ASSERT_EQ(1U, s.size());
EXPECT_EQ(kArm64Float64Max, s[0]->arch_opcode());
ASSERT_EQ(2U, s[0]->InputCount());
EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
ASSERT_EQ(1U, s[0]->OutputCount());
EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
}
TEST_F(InstructionSelectorTest, Float64Min) {
StreamBuilder m(this, kMachFloat64, kMachFloat64, kMachFloat64);
Node* const p0 = m.Parameter(0);
Node* const p1 = m.Parameter(1);
Node* const n = m.Float64Min(p0, p1);
m.Return(n);
Stream s = m.Build();
// Float64Min is `(a < b) ? a : b`.
ASSERT_EQ(1U, s.size());
EXPECT_EQ(kArm64Float64Min, s[0]->arch_opcode());
ASSERT_EQ(2U, s[0]->InputCount());
EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
ASSERT_EQ(1U, s[0]->OutputCount());
EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
}
} // namespace compiler
} // namespace internal
} // namespace v8
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