[arm] Fix recognition of VNEG.
authorBenedikt Meurer <bmeurer@chromium.org>
Wed, 26 Nov 2014 10:46:22 +0000 (11:46 +0100)
committerBenedikt Meurer <bmeurer@chromium.org>
Wed, 26 Nov 2014 10:46:37 +0000 (10:46 +0000)
TEST=mjsunit,unittests
R=svenpanne@chromium.org

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

Cr-Commit-Position: refs/heads/master@{#25513}

src/compiler/arm/instruction-selector-arm.cc
src/compiler/node-matchers.h
test/mjsunit/asm/float64mul.js
test/unittests/compiler/arm/instruction-selector-arm-unittest.cc

index 6e1e084..7d3243e 100644 (file)
@@ -854,16 +854,16 @@ void InstructionSelector::VisitTruncateFloat64ToFloat32(Node* node) {
 
 void InstructionSelector::VisitFloat64Add(Node* node) {
   ArmOperandGenerator g(this);
-  Int32BinopMatcher m(node);
+  Float64BinopMatcher m(node);
   if (m.left().IsFloat64Mul() && CanCover(node, m.left().node())) {
-    Int32BinopMatcher mleft(m.left().node());
+    Float64BinopMatcher mleft(m.left().node());
     Emit(kArmVmlaF64, g.DefineSameAsFirst(node),
          g.UseRegister(m.right().node()), g.UseRegister(mleft.left().node()),
          g.UseRegister(mleft.right().node()));
     return;
   }
   if (m.right().IsFloat64Mul() && CanCover(node, m.right().node())) {
-    Int32BinopMatcher mright(m.right().node());
+    Float64BinopMatcher mright(m.right().node());
     Emit(kArmVmlaF64, g.DefineSameAsFirst(node), g.UseRegister(m.left().node()),
          g.UseRegister(mright.left().node()),
          g.UseRegister(mright.right().node()));
@@ -875,9 +875,14 @@ void InstructionSelector::VisitFloat64Add(Node* node) {
 
 void InstructionSelector::VisitFloat64Sub(Node* node) {
   ArmOperandGenerator g(this);
-  Int32BinopMatcher m(node);
+  Float64BinopMatcher m(node);
+  if (m.left().IsMinusZero()) {
+    Emit(kArmVnegF64, g.DefineAsRegister(node),
+         g.UseRegister(m.right().node()));
+    return;
+  }
   if (m.right().IsFloat64Mul() && CanCover(node, m.right().node())) {
-    Int32BinopMatcher mright(m.right().node());
+    Float64BinopMatcher mright(m.right().node());
     Emit(kArmVmlsF64, g.DefineSameAsFirst(node), g.UseRegister(m.left().node()),
          g.UseRegister(mright.left().node()),
          g.UseRegister(mright.right().node()));
@@ -888,13 +893,7 @@ void InstructionSelector::VisitFloat64Sub(Node* node) {
 
 
 void InstructionSelector::VisitFloat64Mul(Node* node) {
-  ArmOperandGenerator g(this);
-  Float64BinopMatcher m(node);
-  if (m.right().Is(-1.0)) {
-    Emit(kArmVnegF64, g.DefineAsRegister(node), g.UseRegister(m.left().node()));
-  } else {
-    VisitRRRFloat64(this, kArmVmulF64, node);
-  }
+  VisitRRRFloat64(this, kArmVmulF64, node);
 }
 
 
index ebb7722..7f2fcb4 100644 (file)
@@ -5,6 +5,8 @@
 #ifndef V8_COMPILER_NODE_MATCHERS_H_
 #define V8_COMPILER_NODE_MATCHERS_H_
 
+#include <cmath>
+
 #include "src/compiler/generic-node.h"
 #include "src/compiler/generic-node-inl.h"
 #include "src/compiler/node.h"
@@ -104,6 +106,7 @@ template <typename T, IrOpcode::Value kOpcode>
 struct FloatMatcher FINAL : public ValueMatcher<T, kOpcode> {
   explicit FloatMatcher(Node* node) : ValueMatcher<T, kOpcode>(node) {}
 
+  bool IsMinusZero() const { return this->Is(0.0) && signbit(this->Value()); }
   bool IsNaN() const { return this->HasValue() && std::isnan(this->Value()); }
 };
 
@@ -167,6 +170,7 @@ typedef BinopMatcher<UintPtrMatcher, UintPtrMatcher> UintPtrBinopMatcher;
 typedef BinopMatcher<Float64Matcher, Float64Matcher> Float64BinopMatcher;
 typedef BinopMatcher<NumberMatcher, NumberMatcher> NumberBinopMatcher;
 
+
 template <class BinopMatcher, IrOpcode::Value kAddOpcode,
           IrOpcode::Value kMulOpcode, IrOpcode::Value kShiftOpcode>
 struct AddMatcher : public BinopMatcher {
index 3896ec4..9cd9582 100644 (file)
@@ -12,22 +12,32 @@ function Module(stdlib, foreign, heap) {
     i = +i;
     return +(-1 * i);
   }
-  return { f1: f1, f2: f2 };
+  function f3(i) {
+    i = +i;
+    return +(-i);
+  }
+  return { f1: f1, f2: f2, f3: f3 };
 }
 
 var m = Module(this, {}, new ArrayBuffer(64 * 1024));
 
 assertEquals(NaN, m.f1(NaN));
 assertEquals(NaN, m.f2(NaN));
+assertEquals(NaN, m.f3(NaN));
 assertEquals(Infinity, 1 / m.f1(-0));
 assertEquals(Infinity, 1 / m.f2(-0));
+assertEquals(Infinity, 1 / m.f3(-0));
 assertEquals(Infinity, m.f1(-Infinity));
 assertEquals(Infinity, m.f2(-Infinity));
+assertEquals(Infinity, m.f3(-Infinity));
 assertEquals(-Infinity, 1 / m.f1(0));
 assertEquals(-Infinity, 1 / m.f2(0));
+assertEquals(-Infinity, 1 / m.f3(0));
 assertEquals(-Infinity, m.f1(Infinity));
 assertEquals(-Infinity, m.f2(Infinity));
+assertEquals(-Infinity, m.f3(Infinity));
 for (var i = -2147483648; i < 2147483648; i += 3999777) {
   assertEquals(-i, m.f1(i));
   assertEquals(-i, m.f2(i));
+  assertEquals(-i, m.f3(i));
 }
index f922d62..fbdf87a 100644 (file)
@@ -1482,6 +1482,21 @@ INSTANTIATE_TEST_CASE_P(InstructionSelectorTest,
 // Miscellaneous.
 
 
+TEST_F(InstructionSelectorTest, Float64SubWithMinusZero) {
+  StreamBuilder m(this, kMachFloat64, kMachFloat64);
+  Node* const p0 = m.Parameter(0);
+  Node* const n = m.Float64Sub(m.Float64Constant(-0.0), p0);
+  m.Return(n);
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kArmVnegF64, s[0]->arch_opcode());
+  ASSERT_EQ(1U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+  ASSERT_EQ(1U, s[0]->OutputCount());
+  EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
+}
+
+
 TEST_F(InstructionSelectorTest, Int32AddWithInt32Mul) {
   {
     StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32, kMachInt32);