[turbofan] Add new Float32Abs and Float64Abs operators.
authorBenedikt Meurer <bmeurer@chromium.org>
Wed, 8 Apr 2015 11:54:53 +0000 (13:54 +0200)
committerBenedikt Meurer <bmeurer@chromium.org>
Wed, 8 Apr 2015 11:55:04 +0000 (11:55 +0000)
These operators compute the absolute floating point value of some
arbitrary input, and are implemented without any branches (i.e. using
vabs on arm, and andps/andpd on x86).

R=svenpanne@chromium.org

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

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

37 files changed:
src/compiler/arm/code-generator-arm.cc
src/compiler/arm/instruction-codes-arm.h
src/compiler/arm/instruction-selector-arm.cc
src/compiler/arm64/code-generator-arm64.cc
src/compiler/arm64/instruction-codes-arm64.h
src/compiler/arm64/instruction-selector-arm64.cc
src/compiler/common-operator-reducer.cc
src/compiler/common-operator-reducer.h
src/compiler/ia32/code-generator-ia32.cc
src/compiler/ia32/instruction-codes-ia32.h
src/compiler/ia32/instruction-selector-ia32.cc
src/compiler/instruction-selector.cc
src/compiler/machine-operator.cc
src/compiler/machine-operator.h
src/compiler/mips/instruction-selector-mips.cc
src/compiler/mips64/instruction-selector-mips64.cc
src/compiler/node-matchers.h
src/compiler/opcodes.h
src/compiler/ppc/instruction-selector-ppc.cc
src/compiler/raw-machine-assembler.h
src/compiler/simplified-lowering.cc
src/compiler/typer.cc
src/compiler/verifier.cc
src/compiler/x64/code-generator-x64.cc
src/compiler/x64/instruction-codes-x64.h
src/compiler/x64/instruction-selector-x64.cc
src/math.js
test/cctest/compiler/test-run-machops.cc
test/cctest/compiler/value-helper.h
test/unittests/compiler/arm/instruction-selector-arm-unittest.cc
test/unittests/compiler/arm64/instruction-selector-arm64-unittest.cc
test/unittests/compiler/common-operator-reducer-unittest.cc
test/unittests/compiler/ia32/instruction-selector-ia32-unittest.cc
test/unittests/compiler/machine-operator-unittest.cc
test/unittests/compiler/node-test-utils.cc
test/unittests/compiler/node-test-utils.h
test/unittests/compiler/x64/instruction-selector-x64-unittest.cc

index 830e040c5f0f46f7a9d559acbc987674f8c5581e..6ea5e1bde2c22347b16eeeededd3d657f163cc46 100644 (file)
@@ -554,6 +554,9 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
     case kArmVsqrtF32:
       __ vsqrt(i.OutputFloat32Register(), i.InputFloat32Register(0));
       break;
+    case kArmVabsF32:
+      __ vabs(i.OutputFloat32Register(), i.InputFloat32Register(0));
+      break;
     case kArmVnegF32:
       __ vneg(i.OutputFloat32Register(), i.InputFloat32Register(0));
       break;
@@ -616,6 +619,9 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
     case kArmVsqrtF64:
       __ vsqrt(i.OutputFloat64Register(), i.InputFloat64Register(0));
       break;
+    case kArmVabsF64:
+      __ vabs(i.OutputFloat64Register(), i.InputFloat64Register(0));
+      break;
     case kArmVnegF64:
       __ vneg(i.OutputFloat64Register(), i.InputFloat64Register(0));
       break;
@@ -805,7 +811,7 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
       ASSEMBLE_CHECKED_STORE_FLOAT(64);
       break;
   }
-}
+}  // NOLINT(readability/fn_size)
 
 
 // Assembles branches after an instruction.
index 94d1dc33b3b221414531d1be44b6af88f7c13141..377fd8672c3ddc6bb1eab2aedb03658c040c64cb 100644 (file)
@@ -51,6 +51,7 @@ namespace compiler {
   V(ArmVmlaF32)                    \
   V(ArmVmlsF32)                    \
   V(ArmVdivF32)                    \
+  V(ArmVabsF32)                    \
   V(ArmVnegF32)                    \
   V(ArmVsqrtF32)                   \
   V(ArmVcmpF64)                    \
@@ -61,6 +62,7 @@ namespace compiler {
   V(ArmVmlsF64)                    \
   V(ArmVdivF64)                    \
   V(ArmVmodF64)                    \
+  V(ArmVabsF64)                    \
   V(ArmVnegF64)                    \
   V(ArmVsqrtF64)                   \
   V(ArmVrintmF64)                  \
index 8ec4dedd218e8c642d6a0689071b529e40fe39e1..f0040474f4a6ae416d08c1615fbf8e8aee2e8c26 100644 (file)
@@ -1044,6 +1044,16 @@ void InstructionSelector::VisitFloat32Min(Node* node) { UNREACHABLE(); }
 void InstructionSelector::VisitFloat64Min(Node* node) { UNREACHABLE(); }
 
 
+void InstructionSelector::VisitFloat32Abs(Node* node) {
+  VisitRR(this, kArmVabsF32, node);
+}
+
+
+void InstructionSelector::VisitFloat64Abs(Node* node) {
+  VisitRR(this, kArmVabsF64, node);
+}
+
+
 void InstructionSelector::VisitFloat32Sqrt(Node* node) {
   VisitRR(this, kArmVsqrtF32, node);
 }
@@ -1502,6 +1512,8 @@ void InstructionSelector::VisitFloat64InsertHighWord32(Node* node) {
 MachineOperatorBuilder::Flags
 InstructionSelector::SupportedMachineOperatorFlags() {
   MachineOperatorBuilder::Flags flags =
+      MachineOperatorBuilder::kFloat32Abs |
+      MachineOperatorBuilder::kFloat64Abs |
       MachineOperatorBuilder::kInt32DivIsSafe |
       MachineOperatorBuilder::kUint32DivIsSafe;
 
index 2c0e8f5cdc2785a25cbb7110330da36be6969285..762b57a6bc2a8778bdd4f0a3b368e155e1a92953 100644 (file)
@@ -688,6 +688,9 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
       __ Fmin(i.OutputFloat32Register(), i.InputFloat32Register(0),
               i.InputFloat32Register(1));
       break;
+    case kArm64Float32Abs:
+      __ Fabs(i.OutputFloat32Register(), i.InputFloat32Register(0));
+      break;
     case kArm64Float32Sqrt:
       __ Fsqrt(i.OutputFloat32Register(), i.InputFloat32Register(0));
       break;
@@ -736,6 +739,9 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
       __ Fmin(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
               i.InputDoubleRegister(1));
       break;
+    case kArm64Float64Abs:
+      __ Fabs(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
+      break;
     case kArm64Float64Neg:
       __ Fneg(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
       break;
index 2d473ad1f7c1905f1a1a938f0e4a592599cc39a4..3a6037bc5dafdbfc269d983b0ce2c86318f8ba79 100644 (file)
@@ -85,6 +85,7 @@ namespace compiler {
   V(Arm64Float32Div)               \
   V(Arm64Float32Max)               \
   V(Arm64Float32Min)               \
+  V(Arm64Float32Abs)               \
   V(Arm64Float32Sqrt)              \
   V(Arm64Float64Cmp)               \
   V(Arm64Float64Add)               \
@@ -94,6 +95,7 @@ namespace compiler {
   V(Arm64Float64Mod)               \
   V(Arm64Float64Max)               \
   V(Arm64Float64Min)               \
+  V(Arm64Float64Abs)               \
   V(Arm64Float64Neg)               \
   V(Arm64Float64Sqrt)              \
   V(Arm64Float64RoundDown)         \
index 053ae8f53da9183022e246f1bf33c39c7b635df8..e8be0d85311b96cbf1f66fb5b855afddb13d9c2f 100644 (file)
@@ -1169,6 +1169,16 @@ void InstructionSelector::VisitFloat64Min(Node* node) {
 }
 
 
+void InstructionSelector::VisitFloat32Abs(Node* node) {
+  VisitRR(this, kArm64Float32Abs, node);
+}
+
+
+void InstructionSelector::VisitFloat64Abs(Node* node) {
+  VisitRR(this, kArm64Float64Abs, node);
+}
+
+
 void InstructionSelector::VisitFloat32Sqrt(Node* node) {
   VisitRR(this, kArm64Float32Sqrt, node);
 }
@@ -1753,8 +1763,10 @@ void InstructionSelector::VisitFloat64InsertHighWord32(Node* node) {
 // static
 MachineOperatorBuilder::Flags
 InstructionSelector::SupportedMachineOperatorFlags() {
-  return MachineOperatorBuilder::kFloat32Max |
+  return MachineOperatorBuilder::kFloat32Abs |
+         MachineOperatorBuilder::kFloat32Max |
          MachineOperatorBuilder::kFloat32Min |
+         MachineOperatorBuilder::kFloat64Abs |
          MachineOperatorBuilder::kFloat64Max |
          MachineOperatorBuilder::kFloat64Min |
          MachineOperatorBuilder::kFloat64RoundDown |
index c66cce0538794f8019fba27966bc3181b088113d..8001961d37215c8b57ddaac7ea0ebbc5e6a38d7a 100644 (file)
@@ -55,21 +55,39 @@ Reduction CommonOperatorReducer::ReducePhi(Node* node) {
     if (matcher.Matched()) {
       if (matcher.IfTrue() == merge->InputAt(1)) std::swap(vtrue, vfalse);
       Node* cond = matcher.Branch()->InputAt(0);
-      if (cond->opcode() == IrOpcode::kFloat64LessThan) {
-        if (cond->InputAt(0) == vtrue && cond->InputAt(1) == vfalse &&
+      if (cond->opcode() == IrOpcode::kFloat32LessThan) {
+        Float32BinopMatcher mcond(cond);
+        if (mcond.left().Is(0.0) && mcond.right().Equals(vtrue) &&
+            vfalse->opcode() == IrOpcode::kFloat32Sub &&
+            machine()->HasFloat32Abs()) {
+          Float32BinopMatcher mvfalse(vfalse);
+          if (mvfalse.left().IsZero() && mvfalse.right().Equals(vtrue)) {
+            return Change(node, machine()->Float32Abs(), vtrue);
+          }
+        }
+        if (mcond.left().Equals(vtrue) && mcond.right().Equals(vfalse) &&
+            machine()->HasFloat32Min()) {
+          return Change(node, machine()->Float32Min(), vtrue, vfalse);
+        } else if (mcond.left().Equals(vfalse) && mcond.right().Equals(vtrue) &&
+                   machine()->HasFloat32Max()) {
+          return Change(node, machine()->Float32Max(), vtrue, vfalse);
+        }
+      } else if (cond->opcode() == IrOpcode::kFloat64LessThan) {
+        Float64BinopMatcher mcond(cond);
+        if (mcond.left().Is(0.0) && mcond.right().Equals(vtrue) &&
+            vfalse->opcode() == IrOpcode::kFloat64Sub &&
+            machine()->HasFloat64Abs()) {
+          Float64BinopMatcher mvfalse(vfalse);
+          if (mvfalse.left().IsZero() && mvfalse.right().Equals(vtrue)) {
+            return Change(node, machine()->Float64Abs(), vtrue);
+          }
+        }
+        if (mcond.left().Equals(vtrue) && mcond.right().Equals(vfalse) &&
             machine()->HasFloat64Min()) {
-          node->set_op(machine()->Float64Min());
-          node->ReplaceInput(0, vtrue);
-          node->ReplaceInput(1, vfalse);
-          node->TrimInputCount(2);
-          return Changed(node);
-        } else if (cond->InputAt(0) == vfalse && cond->InputAt(1) == vtrue &&
+          return Change(node, machine()->Float64Min(), vtrue, vfalse);
+        } else if (mcond.left().Equals(vfalse) && mcond.right().Equals(vtrue) &&
                    machine()->HasFloat64Max()) {
-          node->set_op(machine()->Float64Max());
-          node->ReplaceInput(0, vtrue);
-          node->ReplaceInput(1, vfalse);
-          node->TrimInputCount(2);
-          return Changed(node);
+          return Change(node, machine()->Float64Max(), vtrue, vfalse);
         }
       }
     }
@@ -91,27 +109,64 @@ Reduction CommonOperatorReducer::ReduceSelect(Node* node) {
   Node* vtrue = NodeProperties::GetValueInput(node, 1);
   Node* vfalse = NodeProperties::GetValueInput(node, 2);
   if (vtrue == vfalse) return Replace(vtrue);
-  if (cond->opcode() == IrOpcode::kFloat64LessThan) {
-    if (cond->InputAt(0) == vtrue && cond->InputAt(1) == vfalse &&
+  if (cond->opcode() == IrOpcode::kFloat32LessThan) {
+    Float32BinopMatcher mcond(cond);
+    if (mcond.left().Is(0.0) && mcond.right().Equals(vtrue) &&
+        vfalse->opcode() == IrOpcode::kFloat32Sub &&
+        machine()->HasFloat32Abs()) {
+      Float32BinopMatcher mvfalse(vfalse);
+      if (mvfalse.left().IsZero() && mvfalse.right().Equals(vtrue)) {
+        return Change(node, machine()->Float32Abs(), vtrue);
+      }
+    }
+    if (mcond.left().Equals(vtrue) && mcond.right().Equals(vfalse) &&
+        machine()->HasFloat32Min()) {
+      return Change(node, machine()->Float32Min(), vtrue, vfalse);
+    } else if (mcond.left().Equals(vfalse) && mcond.right().Equals(vtrue) &&
+               machine()->HasFloat32Max()) {
+      return Change(node, machine()->Float32Max(), vtrue, vfalse);
+    }
+  } else if (cond->opcode() == IrOpcode::kFloat64LessThan) {
+    Float64BinopMatcher mcond(cond);
+    if (mcond.left().Is(0.0) && mcond.right().Equals(vtrue) &&
+        vfalse->opcode() == IrOpcode::kFloat64Sub &&
+        machine()->HasFloat64Abs()) {
+      Float64BinopMatcher mvfalse(vfalse);
+      if (mvfalse.left().IsZero() && mvfalse.right().Equals(vtrue)) {
+        return Change(node, machine()->Float64Abs(), vtrue);
+      }
+    }
+    if (mcond.left().Equals(vtrue) && mcond.right().Equals(vfalse) &&
         machine()->HasFloat64Min()) {
-      node->set_op(machine()->Float64Min());
-      node->ReplaceInput(0, vtrue);
-      node->ReplaceInput(1, vfalse);
-      node->TrimInputCount(2);
-      return Changed(node);
-    } else if (cond->InputAt(0) == vfalse && cond->InputAt(1) == vtrue &&
+      return Change(node, machine()->Float64Min(), vtrue, vfalse);
+    } else if (mcond.left().Equals(vfalse) && mcond.right().Equals(vtrue) &&
                machine()->HasFloat64Max()) {
-      node->set_op(machine()->Float64Max());
-      node->ReplaceInput(0, vtrue);
-      node->ReplaceInput(1, vfalse);
-      node->TrimInputCount(2);
-      return Changed(node);
+      return Change(node, machine()->Float64Max(), vtrue, vfalse);
     }
   }
   return NoChange();
 }
 
 
+Reduction CommonOperatorReducer::Change(Node* node, Operator const* op,
+                                        Node* a) {
+  node->set_op(op);
+  node->ReplaceInput(0, a);
+  node->TrimInputCount(1);
+  return Changed(node);
+}
+
+
+Reduction CommonOperatorReducer::Change(Node* node, Operator const* op, Node* a,
+                                        Node* b) {
+  node->set_op(op);
+  node->ReplaceInput(0, a);
+  node->ReplaceInput(1, b);
+  node->TrimInputCount(2);
+  return Changed(node);
+}
+
+
 CommonOperatorBuilder* CommonOperatorReducer::common() const {
   return jsgraph()->common();
 }
index dfcbe295bc47ed9c0fb5361bb2bfdc9574f2bd5a..2a814a0bc767eea4290dd27a5f0c9cccf62d13dc 100644 (file)
@@ -16,6 +16,7 @@ class CommonOperatorBuilder;
 class Graph;
 class JSGraph;
 class MachineOperatorBuilder;
+class Operator;
 
 
 // Performs strength reduction on nodes that have common operators.
@@ -31,6 +32,9 @@ class CommonOperatorReducer FINAL : public Reducer {
   Reduction ReducePhi(Node* node);
   Reduction ReduceSelect(Node* node);
 
+  Reduction Change(Node* node, Operator const* op, Node* a);
+  Reduction Change(Node* node, Operator const* op, Node* a, Node* b);
+
   CommonOperatorBuilder* common() const;
   Graph* graph() const;
   JSGraph* jsgraph() const { return jsgraph_; }
index 19a76e075f5d077cbc2a0cde0cb129006b82fc61..447a8e3b1c75d7302a76c97ccf30543b44efbc57 100644 (file)
@@ -477,6 +477,14 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
     case kSSEFloat32Sqrt:
       __ sqrtss(i.OutputDoubleRegister(), i.InputOperand(0));
       break;
+    case kSSEFloat32Abs: {
+      // TODO(bmeurer): Use 128-bit constants.
+      // TODO(turbofan): Add AVX version with relaxed register constraints.
+      __ pcmpeqd(kScratchDoubleReg, kScratchDoubleReg);
+      __ psrlq(kScratchDoubleReg, 33);
+      __ andps(i.OutputDoubleRegister(), kScratchDoubleReg);
+      break;
+    }
     case kSSEFloat32Neg: {
       // TODO(bmeurer): Use 128-bit constants.
       // TODO(turbofan): Add AVX version with relaxed register constraints.
@@ -531,6 +539,14 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
       __ add(esp, Immediate(kDoubleSize));
       break;
     }
+    case kSSEFloat64Abs: {
+      // TODO(bmeurer): Use 128-bit constants.
+      // TODO(turbofan): Add AVX version with relaxed register constraints.
+      __ pcmpeqd(kScratchDoubleReg, kScratchDoubleReg);
+      __ psrlq(kScratchDoubleReg, 1);
+      __ andpd(i.OutputDoubleRegister(), kScratchDoubleReg);
+      break;
+    }
     case kSSEFloat64Neg: {
       // TODO(bmeurer): Use 128-bit constants.
       // TODO(turbofan): Add AVX version with relaxed register constraints.
index 2037d94110864f287820ca1266eddda057b72288..472dd57e14fdf8328d9b8786ef6bd1f16b8c622b 100644 (file)
@@ -38,6 +38,7 @@ namespace compiler {
   V(SSEFloat32Div)                 \
   V(SSEFloat32Max)                 \
   V(SSEFloat32Min)                 \
+  V(SSEFloat32Abs)                 \
   V(SSEFloat32Neg)                 \
   V(SSEFloat32Sqrt)                \
   V(SSEFloat64Cmp)                 \
@@ -48,6 +49,7 @@ namespace compiler {
   V(SSEFloat64Mod)                 \
   V(SSEFloat64Max)                 \
   V(SSEFloat64Min)                 \
+  V(SSEFloat64Abs)                 \
   V(SSEFloat64Neg)                 \
   V(SSEFloat64Sqrt)                \
   V(SSEFloat64Round)               \
index 8c5c192a79c4750f62e82af78d439b8527a8608c..bf9316039447a2447312a99223c7ee87cdb0473d 100644 (file)
@@ -759,6 +759,18 @@ void InstructionSelector::VisitFloat64Min(Node* node) {
 }
 
 
+void InstructionSelector::VisitFloat32Abs(Node* node) {
+  IA32OperandGenerator g(this);
+  Emit(kSSEFloat32Abs, g.DefineSameAsFirst(node), g.Use(node->InputAt(0)));
+}
+
+
+void InstructionSelector::VisitFloat64Abs(Node* node) {
+  IA32OperandGenerator g(this);
+  Emit(kSSEFloat64Abs, g.DefineSameAsFirst(node), g.Use(node->InputAt(0)));
+}
+
+
 void InstructionSelector::VisitFloat32Sqrt(Node* node) {
   VisitROFloat(this, node, kSSEFloat32Sqrt);
 }
@@ -1196,8 +1208,10 @@ void InstructionSelector::VisitFloat64InsertHighWord32(Node* node) {
 MachineOperatorBuilder::Flags
 InstructionSelector::SupportedMachineOperatorFlags() {
   MachineOperatorBuilder::Flags flags =
+      MachineOperatorBuilder::kFloat32Abs |
       MachineOperatorBuilder::kFloat32Max |
       MachineOperatorBuilder::kFloat32Min |
+      MachineOperatorBuilder::kFloat64Abs |
       MachineOperatorBuilder::kFloat64Max |
       MachineOperatorBuilder::kFloat64Min |
       MachineOperatorBuilder::kWord32ShiftIsSafe;
index 89c2fe1e459f1110b61fbaa0e25bbc2dc0b2d104..b612e3253be0a5d775011b69f3904d51fd8fbe59 100644 (file)
@@ -764,6 +764,8 @@ void InstructionSelector::VisitNode(Node* node) {
       return MarkAsDouble(node), VisitFloat32Min(node);
     case IrOpcode::kFloat32Max:
       return MarkAsDouble(node), VisitFloat32Max(node);
+    case IrOpcode::kFloat32Abs:
+      return MarkAsDouble(node), VisitFloat32Abs(node);
     case IrOpcode::kFloat32Sqrt:
       return MarkAsDouble(node), VisitFloat32Sqrt(node);
     case IrOpcode::kFloat32Equal:
@@ -786,6 +788,8 @@ void InstructionSelector::VisitNode(Node* node) {
       return MarkAsDouble(node), VisitFloat64Min(node);
     case IrOpcode::kFloat64Max:
       return MarkAsDouble(node), VisitFloat64Max(node);
+    case IrOpcode::kFloat64Abs:
+      return MarkAsDouble(node), VisitFloat64Abs(node);
     case IrOpcode::kFloat64Sqrt:
       return MarkAsDouble(node), VisitFloat64Sqrt(node);
     case IrOpcode::kFloat64Equal:
index 76a929213af2814f05d3b71aff4792f85c65e822..bc8256f764148d2f31356dbc65ce6c109ac07aa7 100644 (file)
@@ -122,12 +122,14 @@ CheckedStoreRepresentation CheckedStoreRepresentationOf(Operator const* op) {
   V(Float32Sub, Operator::kNoProperties, 2, 0, 1)                             \
   V(Float32Mul, Operator::kCommutative, 2, 0, 1)                              \
   V(Float32Div, Operator::kNoProperties, 2, 0, 1)                             \
+  V(Float32Abs, Operator::kNoProperties, 1, 0, 1)                             \
   V(Float32Sqrt, Operator::kNoProperties, 1, 0, 1)                            \
   V(Float64Add, Operator::kCommutative, 2, 0, 1)                              \
   V(Float64Sub, Operator::kNoProperties, 2, 0, 1)                             \
   V(Float64Mul, Operator::kCommutative, 2, 0, 1)                              \
   V(Float64Div, Operator::kNoProperties, 2, 0, 1)                             \
   V(Float64Mod, Operator::kNoProperties, 2, 0, 1)                             \
+  V(Float64Abs, Operator::kNoProperties, 1, 0, 1)                             \
   V(Float64Sqrt, Operator::kNoProperties, 1, 0, 1)                            \
   V(Float64RoundDown, Operator::kNoProperties, 1, 0, 1)                       \
   V(Float64RoundTruncate, Operator::kNoProperties, 1, 0, 1)                   \
index 21510bf5a0fa72822b6bfcf2e8b1984a57dd0438..e459ae47dff75355dd8062793a184a848596cf1a 100644 (file)
@@ -74,16 +74,18 @@ class MachineOperatorBuilder FINAL : public ZoneObject {
   // for operations that are unsupported by some back-ends.
   enum Flag {
     kNoFlags = 0u,
-    kFloat32Max = 1u << 0,
-    kFloat32Min = 1u << 1,
-    kFloat64Max = 1u << 2,
-    kFloat64Min = 1u << 3,
-    kFloat64RoundDown = 1u << 4,
-    kFloat64RoundTruncate = 1u << 5,
-    kFloat64RoundTiesAway = 1u << 6,
-    kInt32DivIsSafe = 1u << 7,
-    kUint32DivIsSafe = 1u << 8,
-    kWord32ShiftIsSafe = 1u << 9
+    kFloat32Abs = 1u << 0,
+    kFloat32Max = 1u << 1,
+    kFloat32Min = 1u << 2,
+    kFloat64Abs = 1u << 3,
+    kFloat64Max = 1u << 4,
+    kFloat64Min = 1u << 5,
+    kFloat64RoundDown = 1u << 6,
+    kFloat64RoundTruncate = 1u << 7,
+    kFloat64RoundTiesAway = 1u << 8,
+    kInt32DivIsSafe = 1u << 9,
+    kUint32DivIsSafe = 1u << 10,
+    kWord32ShiftIsSafe = 1u << 11
   };
   typedef base::Flags<Flag, unsigned> Flags;
 
@@ -197,6 +199,14 @@ class MachineOperatorBuilder FINAL : public ZoneObject {
   bool HasFloat64Max() { return flags_ & kFloat64Max; }
   bool HasFloat64Min() { return flags_ & kFloat64Min; }
 
+  // Floating point abs complying to IEEE 754 (single-precision).
+  const Operator* Float32Abs();
+  bool HasFloat32Abs() const { return flags_ & kFloat32Abs; }
+
+  // Floating point abs complying to IEEE 754 (double-precision).
+  const Operator* Float64Abs();
+  bool HasFloat64Abs() const { return flags_ & kFloat64Abs; }
+
   // Floating point rounding.
   const Operator* Float64RoundDown();
   const Operator* Float64RoundTruncate();
index 149d4bc7a7dcf20d48d6f8bfe1272d8a38caee27..61a5a1cfc3f7847a3b2e8dbd0bc0b0514625e09d 100644 (file)
@@ -463,6 +463,12 @@ void InstructionSelector::VisitFloat32Min(Node* node) { UNREACHABLE(); }
 void InstructionSelector::VisitFloat64Min(Node* node) { UNREACHABLE(); }
 
 
+void InstructionSelector::VisitFloat32Abs(Node* node) { UNREACHABLE(); }
+
+
+void InstructionSelector::VisitFloat64Abs(Node* node) { UNREACHABLE(); }
+
+
 void InstructionSelector::VisitFloat32Sqrt(Node* node) {
   VisitRR(this, kMipsSqrtS, node);
 }
index 379ada8a3f8407ee4df360c286fe28e82254cc1f..98497c65fd737aaebbdf7b73d4afd25a56d6aa41 100644 (file)
@@ -612,6 +612,12 @@ void InstructionSelector::VisitFloat32Min(Node* node) { UNREACHABLE(); }
 void InstructionSelector::VisitFloat64Min(Node* node) { UNREACHABLE(); }
 
 
+void InstructionSelector::VisitFloat32Abs(Node* node) { UNREACHABLE(); }
+
+
+void InstructionSelector::VisitFloat64Abs(Node* node) { UNREACHABLE(); }
+
+
 void InstructionSelector::VisitFloat32Sqrt(Node* node) {
   VisitRR(this, kMips64SqrtS, node);
 }
index 6beca7c2c898f32ca0b6df06daddc5b31e0f2a23..e47de294fba82cb5b48e955e55b3a788865e88a0 100644 (file)
@@ -30,6 +30,8 @@ struct NodeMatcher {
   }
   Node* InputAt(int index) const { return node()->InputAt(index); }
 
+  bool Equals(const Node* node) const { return node_ == node; }
+
   bool IsComparison() const;
 
 #define DEFINE_IS_OPCODE(Opcode) \
@@ -141,6 +143,7 @@ struct FloatMatcher FINAL : public ValueMatcher<T, kOpcode> {
     return this->Is(0.0) && std::signbit(this->Value());
   }
   bool IsNaN() const { return this->HasValue() && std::isnan(this->Value()); }
+  bool IsZero() const { return this->Is(0.0) && !std::signbit(this->Value()); }
 };
 
 typedef FloatMatcher<float, IrOpcode::kFloat32Constant> Float32Matcher;
index 18cd9e1506e5106e501efa8e6f98f2ce48b26e49..e79e911c9e21a7232c7a65d875d04f4a295ddc35 100644 (file)
   V(Float32Div)                 \
   V(Float32Max)                 \
   V(Float32Min)                 \
+  V(Float32Abs)                 \
   V(Float32Sqrt)                \
   V(Float64Add)                 \
   V(Float64Sub)                 \
   V(Float64Mod)                 \
   V(Float64Max)                 \
   V(Float64Min)                 \
+  V(Float64Abs)                 \
   V(Float64Sqrt)                \
   V(Float64RoundDown)           \
   V(Float64RoundTruncate)       \
index 9d576bafb7278d32c5baa049adf978f4ee4fce45..28a1649f8fc567c54c1c4753405a08dd655e0542 100644 (file)
@@ -983,6 +983,12 @@ void InstructionSelector::VisitFloat64Min(Node* node) {
 }
 
 
+void InstructionSelector::VisitFloat32Abs(Node* node) { UNREACHABLE(); }
+
+
+void InstructionSelector::VisitFloat64Abs(Node* node) { UNREACHABLE(); }
+
+
 void InstructionSelector::VisitFloat32Sqrt(Node* node) {
   VisitRR(this, kPPC_SqrtDouble, node);
 }
index e9ef97fa7f9c90dcd49ffacbc8a68b3d943e1a8a..edc8f6b1dd04964e7793da41a65a681d25f1c1b9 100644 (file)
@@ -340,6 +340,7 @@ class RawMachineAssembler : public GraphBuilder {
   Node* Float32Div(Node* a, Node* b) {
     return NewNode(machine()->Float32Div(), a, b);
   }
+  Node* Float32Abs(Node* a) { return NewNode(machine()->Float32Abs(), a); }
   Node* Float32Sqrt(Node* a) { return NewNode(machine()->Float32Sqrt(), a); }
   Node* Float32Equal(Node* a, Node* b) {
     return NewNode(machine()->Float32Equal(), a, b);
@@ -373,6 +374,7 @@ class RawMachineAssembler : public GraphBuilder {
   Node* Float64Mod(Node* a, Node* b) {
     return NewNode(machine()->Float64Mod(), a, b);
   }
+  Node* Float64Abs(Node* a) { return NewNode(machine()->Float64Abs(), a); }
   Node* Float64Sqrt(Node* a) { return NewNode(machine()->Float64Sqrt(), a); }
   Node* Float64Equal(Node* a, Node* b) {
     return NewNode(machine()->Float64Equal(), a, b);
index b4080a916e63f83a3842472214082bc939da66c7..02ddb3d413336545ee0f45e3196f41d9878734d7 100644 (file)
@@ -1019,6 +1019,7 @@ class RepresentationSelector {
       case IrOpcode::kFloat64Mod:
       case IrOpcode::kFloat64Min:
         return VisitFloat64Binop(node);
+      case IrOpcode::kFloat64Abs:
       case IrOpcode::kFloat64Sqrt:
       case IrOpcode::kFloat64RoundDown:
       case IrOpcode::kFloat64RoundTruncate:
index 1507f20dc8fd77d0dc3db9ae3afc8c4bfff2f8ce..ae8f14c9acdd5ce3f6c3b431e54491311c1b71a7 100644 (file)
@@ -2134,6 +2134,12 @@ Bounds Typer::Visitor::TypeFloat32Min(Node* node) {
 }
 
 
+Bounds Typer::Visitor::TypeFloat32Abs(Node* node) {
+  // TODO(turbofan): We should be able to infer a better type here.
+  return Bounds(Type::Number());
+}
+
+
 Bounds Typer::Visitor::TypeFloat32Sqrt(Node* node) {
   return Bounds(Type::Number());
 }
@@ -2189,6 +2195,12 @@ Bounds Typer::Visitor::TypeFloat64Min(Node* node) {
 }
 
 
+Bounds Typer::Visitor::TypeFloat64Abs(Node* node) {
+  // TODO(turbofan): We should be able to infer a better type here.
+  return Bounds(Type::Number());
+}
+
+
 Bounds Typer::Visitor::TypeFloat64Sqrt(Node* node) {
   return Bounds(Type::Number());
 }
index e49ed65a1f27fb0542af6f5b20889c7d01475833..fb017166dc8bcae86b14c564a55df5e98d5dfa8a 100644 (file)
@@ -793,6 +793,7 @@ void Verifier::Visitor::Check(Node* node) {
     case IrOpcode::kFloat32Div:
     case IrOpcode::kFloat32Max:
     case IrOpcode::kFloat32Min:
+    case IrOpcode::kFloat32Abs:
     case IrOpcode::kFloat32Sqrt:
     case IrOpcode::kFloat32Equal:
     case IrOpcode::kFloat32LessThan:
@@ -804,6 +805,7 @@ void Verifier::Visitor::Check(Node* node) {
     case IrOpcode::kFloat64Mod:
     case IrOpcode::kFloat64Max:
     case IrOpcode::kFloat64Min:
+    case IrOpcode::kFloat64Abs:
     case IrOpcode::kFloat64Sqrt:
     case IrOpcode::kFloat64RoundDown:
     case IrOpcode::kFloat64RoundTruncate:
index 98ec629b4d702ba2d8d033a34e830ec6b3cc2939..443f1b1efdd4676d601da77cc02c2f5e0971cc6a 100644 (file)
@@ -726,6 +726,14 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
     case kSSEFloat32Div:
       ASSEMBLE_SSE_BINOP(divss);
       break;
+    case kSSEFloat32Abs: {
+      // TODO(bmeurer): Use RIP relative 128-bit constants.
+      // TODO(turbofan): Add AVX version with relaxed register constraints.
+      __ pcmpeqd(kScratchDoubleReg, kScratchDoubleReg);
+      __ psrlq(kScratchDoubleReg, 33);
+      __ andps(i.OutputDoubleRegister(), kScratchDoubleReg);
+      break;
+    }
     case kSSEFloat32Neg: {
       // TODO(bmeurer): Use RIP relative 128-bit constants.
       // TODO(turbofan): Add AVX version with relaxed register constraints.
@@ -799,6 +807,14 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
     case kSSEFloat64Min:
       ASSEMBLE_SSE_BINOP(minsd);
       break;
+    case kSSEFloat64Abs: {
+      // TODO(bmeurer): Use RIP relative 128-bit constants.
+      // TODO(turbofan): Add AVX version with relaxed register constraints.
+      __ pcmpeqd(kScratchDoubleReg, kScratchDoubleReg);
+      __ psrlq(kScratchDoubleReg, 1);
+      __ andpd(i.OutputDoubleRegister(), kScratchDoubleReg);
+      break;
+    }
     case kSSEFloat64Neg: {
       // TODO(bmeurer): Use RIP relative 128-bit constants.
       // TODO(turbofan): Add AVX version with relaxed register constraints.
index 8b0469e1c6d319207f0d5bdbcb2ab3e2d27ed6bd..87e011006899d0ec5c31ca21b1fdc3b64cc5382f 100644 (file)
@@ -52,6 +52,7 @@ namespace compiler {
   V(SSEFloat32Sub)                 \
   V(SSEFloat32Mul)                 \
   V(SSEFloat32Div)                 \
+  V(SSEFloat32Abs)                 \
   V(SSEFloat32Neg)                 \
   V(SSEFloat32Sqrt)                \
   V(SSEFloat32Max)                 \
@@ -63,6 +64,7 @@ namespace compiler {
   V(SSEFloat64Mul)                 \
   V(SSEFloat64Div)                 \
   V(SSEFloat64Mod)                 \
+  V(SSEFloat64Abs)                 \
   V(SSEFloat64Neg)                 \
   V(SSEFloat64Sqrt)                \
   V(SSEFloat64Round)               \
index 82829a88352e8eb5db3e99af5ae5df4077d074ce..fea4e3f6235a8c7e88a62c9ae688669300cfae91 100644 (file)
@@ -889,6 +889,12 @@ void InstructionSelector::VisitFloat32Min(Node* node) {
 }
 
 
+void InstructionSelector::VisitFloat32Abs(Node* node) {
+  X64OperandGenerator g(this);
+  Emit(kSSEFloat32Abs, g.DefineSameAsFirst(node), g.Use(node->InputAt(0)));
+}
+
+
 void InstructionSelector::VisitFloat32Sqrt(Node* node) {
   X64OperandGenerator g(this);
   Emit(kSSEFloat32Sqrt, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
@@ -953,6 +959,12 @@ void InstructionSelector::VisitFloat64Min(Node* node) {
 }
 
 
+void InstructionSelector::VisitFloat64Abs(Node* node) {
+  X64OperandGenerator g(this);
+  Emit(kSSEFloat64Abs, g.DefineSameAsFirst(node), g.Use(node->InputAt(0)));
+}
+
+
 void InstructionSelector::VisitFloat64Sqrt(Node* node) {
   X64OperandGenerator g(this);
   Emit(kSSEFloat64Sqrt, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
@@ -1508,8 +1520,10 @@ void InstructionSelector::VisitFloat64InsertHighWord32(Node* node) {
 MachineOperatorBuilder::Flags
 InstructionSelector::SupportedMachineOperatorFlags() {
   MachineOperatorBuilder::Flags flags =
+      MachineOperatorBuilder::kFloat32Abs |
       MachineOperatorBuilder::kFloat32Max |
       MachineOperatorBuilder::kFloat32Min |
+      MachineOperatorBuilder::kFloat64Abs |
       MachineOperatorBuilder::kFloat64Max |
       MachineOperatorBuilder::kFloat64Min |
       MachineOperatorBuilder::kWord32ShiftIsSafe;
index b802de0f461130cf01cb71e864e9ae69e0af1829..20f36e6bb1ae7cd4dec997a941a45baa25a9446a 100644 (file)
@@ -24,8 +24,7 @@ var GlobalArray = global.Array;
 // ECMA 262 - 15.8.2.1
 function MathAbs(x) {
   x = +x;
-  if (x > 0) return x;
-  return 0 - x;
+  return (x > 0) ? x : 0 - x;
 }
 
 // ECMA 262 - 15.8.2.2
index 1686d377883e9c68898e301461b46d36a384384a..9c143caa7df556633763680e0d28a8b24202a1b2 100644 (file)
@@ -4945,6 +4945,40 @@ TEST(RunFloat64InsertHighWord32) {
 }
 
 
+TEST(RunFloat32Abs) {
+  float input = -1.0;
+  float result = 0.0;
+  RawMachineAssemblerTester<int32_t> m;
+  if (!m.machine()->HasFloat32Abs()) return;
+  m.StoreToPointer(&result, kMachFloat32,
+                   m.Float32Abs(m.LoadFromPointer(&input, kMachFloat32)));
+  m.Return(m.Int32Constant(0));
+  FOR_FLOAT32_INPUTS(i) {
+    input = *i;
+    float expected = std::abs(input);
+    CHECK_EQ(0, m.Call());
+    CheckFloatEq(expected, result);
+  }
+}
+
+
+TEST(RunFloat64Abs) {
+  double input = -1.0;
+  double result = 0.0;
+  RawMachineAssemblerTester<int32_t> m;
+  if (!m.machine()->HasFloat64Abs()) return;
+  m.StoreToPointer(&result, kMachFloat64,
+                   m.Float64Abs(m.LoadFromPointer(&input, kMachFloat64)));
+  m.Return(m.Int32Constant(0));
+  FOR_FLOAT64_INPUTS(i) {
+    input = *i;
+    double expected = std::abs(input);
+    CHECK_EQ(0, m.Call());
+    CheckDoubleEq(expected, result);
+  }
+}
+
+
 static double two_30 = 1 << 30;             // 2^30 is a smi boundary.
 static double two_52 = two_30 * (1 << 22);  // 2^52 is a precision boundary.
 static double kValues[] = {0.1,
index 208fa437c25fe29c4c0145b1532797c65491ea78..b5931fb30e9538121100f84ffb3513dbdeac5e94 100644 (file)
@@ -102,14 +102,12 @@ class ValueHelper {
   static std::vector<double> float64_vector() {
     static const double nan = std::numeric_limits<double>::quiet_NaN();
     static const double values[] = {
-        0.125,           0.25,            0.375,          0.5,
-        1.25,            -1.75,           2,              5.125,
-        6.25,            0.0,             -0.0,           982983.25,
-        888,             2147483647.0,    -999.75,        3.1e7,
-        -2e66,           3e-88,           -2147483648.0,  V8_INFINITY,
-        -V8_INFINITY,    nan,             2147483647.375, 2147483647.75,
-        2147483648.0,    2147483648.25,   2147483649.25,  -2147483647.0,
-        -2147483647.125, -2147483647.875, -2147483648.25, -2147483649.5};
+        0.125, 0.25, 0.375, 0.5, 1.25, -1.75, 2, 5.125, 6.25, 0.0, -0.0,
+        982983.25, 888, 2147483647.0, -999.75, 3.1e7, -2e66, 3e-88,
+        -2147483648.0, V8_INFINITY, -V8_INFINITY, -nan, nan, 2147483647.375,
+        2147483647.75, 2147483648.0, 2147483648.25, 2147483649.25,
+        -2147483647.0, -2147483647.125, -2147483647.875, -2147483648.25,
+        -2147483649.5};
     return std::vector<double>(&values[0], &values[arraysize(values)]);
   }
 
index 8534c1c79a72d86a70636ded0f18216c4da24b30..1bc23e6e0aeab7dea31bd0b0b47ea4410ee87558 100644 (file)
@@ -1679,6 +1679,36 @@ INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorFAITest,
                         ::testing::ValuesIn(kFAIs));
 
 
+TEST_F(InstructionSelectorTest, Float32Abs) {
+  StreamBuilder m(this, kMachFloat32, kMachFloat32);
+  Node* const p0 = m.Parameter(0);
+  Node* const n = m.Float32Abs(p0);
+  m.Return(n);
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kArmVabsF32, 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, Float64Abs) {
+  StreamBuilder m(this, kMachFloat64, kMachFloat64);
+  Node* const p0 = m.Parameter(0);
+  Node* const n = m.Float64Abs(p0);
+  m.Return(n);
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kArmVabsF64, 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, Float32AddWithFloat32Mul) {
   {
     StreamBuilder m(this, kMachFloat32, kMachFloat32, kMachFloat32,
index 85b08e99ad10579061bb0afefa3a96b49b322319..cd825e239ba421a84678182a10b67d724bb3a1ce 100644 (file)
@@ -2412,6 +2412,36 @@ TEST_F(InstructionSelectorTest, Word32Clz) {
 }
 
 
+TEST_F(InstructionSelectorTest, Float32Abs) {
+  StreamBuilder m(this, kMachFloat32, kMachFloat32);
+  Node* const p0 = m.Parameter(0);
+  Node* const n = m.Float32Abs(p0);
+  m.Return(n);
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kArm64Float32Abs, 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, Float64Abs) {
+  StreamBuilder m(this, kMachFloat64, kMachFloat64);
+  Node* const p0 = m.Parameter(0);
+  Node* const n = m.Float64Abs(p0);
+  m.Return(n);
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kArm64Float64Abs, 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, Float64SubWithMinusZero) {
   StreamBuilder m(this, kMachFloat64, kMachFloat64);
   Node* const p0 = m.Parameter(0);
index 3b60e5b9bd32b2218b1fe33e6af30bccbbae61ad..ce10b1e63593729feb3bdafcf3da00315e52aa81 100644 (file)
@@ -108,7 +108,88 @@ TEST_F(CommonOperatorReducerTest, RedundantPhi) {
 }
 
 
-TEST_F(CommonOperatorReducerTest, PhiToFloat64MaxOrFloat64Min) {
+TEST_F(CommonOperatorReducerTest, PhiToFloat32Abs) {
+  Node* p0 = Parameter(0);
+  Node* c0 = Float32Constant(0.0);
+  Node* check = graph()->NewNode(machine()->Float32LessThan(), c0, p0);
+  Node* branch = graph()->NewNode(common()->Branch(), check, graph()->start());
+  Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
+  Node* vtrue = p0;
+  Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
+  Node* vfalse = graph()->NewNode(machine()->Float32Sub(), c0, p0);
+  Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
+  Node* phi =
+      graph()->NewNode(common()->Phi(kMachFloat32, 2), vtrue, vfalse, merge);
+  Reduction r = Reduce(phi, MachineOperatorBuilder::kFloat32Abs);
+  ASSERT_TRUE(r.Changed());
+  EXPECT_THAT(r.replacement(), IsFloat32Abs(p0));
+}
+
+
+TEST_F(CommonOperatorReducerTest, PhiToFloat64Abs) {
+  Node* p0 = Parameter(0);
+  Node* c0 = Float64Constant(0.0);
+  Node* check = graph()->NewNode(machine()->Float64LessThan(), c0, p0);
+  Node* branch = graph()->NewNode(common()->Branch(), check, graph()->start());
+  Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
+  Node* vtrue = p0;
+  Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
+  Node* vfalse = graph()->NewNode(machine()->Float64Sub(), c0, p0);
+  Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
+  Node* phi =
+      graph()->NewNode(common()->Phi(kMachFloat64, 2), vtrue, vfalse, merge);
+  Reduction r = Reduce(phi, MachineOperatorBuilder::kFloat64Abs);
+  ASSERT_TRUE(r.Changed());
+  EXPECT_THAT(r.replacement(), IsFloat64Abs(p0));
+}
+
+
+TEST_F(CommonOperatorReducerTest, PhiToFloat32Max) {
+  Node* p0 = Parameter(0);
+  Node* p1 = Parameter(1);
+  Node* check = graph()->NewNode(machine()->Float32LessThan(), p0, p1);
+  Node* branch = graph()->NewNode(common()->Branch(), check, graph()->start());
+  Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
+  Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
+  Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
+  Node* phi = graph()->NewNode(common()->Phi(kMachFloat32, 2), p1, p0, merge);
+  Reduction r = Reduce(phi, MachineOperatorBuilder::kFloat32Max);
+  ASSERT_TRUE(r.Changed());
+  EXPECT_THAT(r.replacement(), IsFloat32Max(p1, p0));
+}
+
+
+TEST_F(CommonOperatorReducerTest, PhiToFloat64Max) {
+  Node* p0 = Parameter(0);
+  Node* p1 = Parameter(1);
+  Node* check = graph()->NewNode(machine()->Float64LessThan(), p0, p1);
+  Node* branch = graph()->NewNode(common()->Branch(), check, graph()->start());
+  Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
+  Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
+  Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
+  Node* phi = graph()->NewNode(common()->Phi(kMachFloat64, 2), p1, p0, merge);
+  Reduction r = Reduce(phi, MachineOperatorBuilder::kFloat64Max);
+  ASSERT_TRUE(r.Changed());
+  EXPECT_THAT(r.replacement(), IsFloat64Max(p1, p0));
+}
+
+
+TEST_F(CommonOperatorReducerTest, PhiToFloat32Min) {
+  Node* p0 = Parameter(0);
+  Node* p1 = Parameter(1);
+  Node* check = graph()->NewNode(machine()->Float32LessThan(), p0, p1);
+  Node* branch = graph()->NewNode(common()->Branch(), check, graph()->start());
+  Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
+  Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
+  Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
+  Node* phi = graph()->NewNode(common()->Phi(kMachFloat32, 2), p0, p1, merge);
+  Reduction r = Reduce(phi, MachineOperatorBuilder::kFloat32Min);
+  ASSERT_TRUE(r.Changed());
+  EXPECT_THAT(r.replacement(), IsFloat32Min(p0, p1));
+}
+
+
+TEST_F(CommonOperatorReducerTest, PhiToFloat64Min) {
   Node* p0 = Parameter(0);
   Node* p1 = Parameter(1);
   Node* check = graph()->NewNode(machine()->Float64LessThan(), p0, p1);
@@ -116,16 +197,10 @@ TEST_F(CommonOperatorReducerTest, PhiToFloat64MaxOrFloat64Min) {
   Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
   Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
   Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
-  Reduction r1 =
-      Reduce(graph()->NewNode(common()->Phi(kMachFloat64, 2), p1, p0, merge),
-             MachineOperatorBuilder::kFloat64Max);
-  ASSERT_TRUE(r1.Changed());
-  EXPECT_THAT(r1.replacement(), IsFloat64Max(p1, p0));
-  Reduction r2 =
-      Reduce(graph()->NewNode(common()->Phi(kMachFloat64, 2), p0, p1, merge),
-             MachineOperatorBuilder::kFloat64Min);
-  ASSERT_TRUE(r2.Changed());
-  EXPECT_THAT(r2.replacement(), IsFloat64Min(p0, p1));
+  Node* phi = graph()->NewNode(common()->Phi(kMachFloat64, 2), p0, p1, merge);
+  Reduction r = Reduce(phi, MachineOperatorBuilder::kFloat64Min);
+  ASSERT_TRUE(r.Changed());
+  EXPECT_THAT(r.replacement(), IsFloat64Min(p0, p1));
 }
 
 
@@ -146,20 +221,77 @@ TEST_F(CommonOperatorReducerTest, RedundantSelect) {
 }
 
 
-TEST_F(CommonOperatorReducerTest, SelectToFloat64MaxOrFloat64Min) {
+TEST_F(CommonOperatorReducerTest, SelectToFloat32Abs) {
+  Node* p0 = Parameter(0);
+  Node* c0 = Float32Constant(0.0);
+  Node* check = graph()->NewNode(machine()->Float32LessThan(), c0, p0);
+  Node* select =
+      graph()->NewNode(common()->Select(kMachFloat32), check, p0,
+                       graph()->NewNode(machine()->Float32Sub(), c0, p0));
+  Reduction r = Reduce(select, MachineOperatorBuilder::kFloat32Abs);
+  ASSERT_TRUE(r.Changed());
+  EXPECT_THAT(r.replacement(), IsFloat32Abs(p0));
+}
+
+
+TEST_F(CommonOperatorReducerTest, SelectToFloat64Abs) {
+  Node* p0 = Parameter(0);
+  Node* c0 = Float64Constant(0.0);
+  Node* check = graph()->NewNode(machine()->Float64LessThan(), c0, p0);
+  Node* select =
+      graph()->NewNode(common()->Select(kMachFloat64), check, p0,
+                       graph()->NewNode(machine()->Float64Sub(), c0, p0));
+  Reduction r = Reduce(select, MachineOperatorBuilder::kFloat64Abs);
+  ASSERT_TRUE(r.Changed());
+  EXPECT_THAT(r.replacement(), IsFloat64Abs(p0));
+}
+
+
+TEST_F(CommonOperatorReducerTest, SelectToFloat32Max) {
+  Node* p0 = Parameter(0);
+  Node* p1 = Parameter(1);
+  Node* check = graph()->NewNode(machine()->Float32LessThan(), p0, p1);
+  Node* select =
+      graph()->NewNode(common()->Select(kMachFloat32), check, p1, p0);
+  Reduction r = Reduce(select, MachineOperatorBuilder::kFloat32Max);
+  ASSERT_TRUE(r.Changed());
+  EXPECT_THAT(r.replacement(), IsFloat32Max(p1, p0));
+}
+
+
+TEST_F(CommonOperatorReducerTest, SelectToFloat64Max) {
+  Node* p0 = Parameter(0);
+  Node* p1 = Parameter(1);
+  Node* check = graph()->NewNode(machine()->Float64LessThan(), p0, p1);
+  Node* select =
+      graph()->NewNode(common()->Select(kMachFloat64), check, p1, p0);
+  Reduction r = Reduce(select, MachineOperatorBuilder::kFloat64Max);
+  ASSERT_TRUE(r.Changed());
+  EXPECT_THAT(r.replacement(), IsFloat64Max(p1, p0));
+}
+
+
+TEST_F(CommonOperatorReducerTest, SelectToFloat32Min) {
+  Node* p0 = Parameter(0);
+  Node* p1 = Parameter(1);
+  Node* check = graph()->NewNode(machine()->Float32LessThan(), p0, p1);
+  Node* select =
+      graph()->NewNode(common()->Select(kMachFloat32), check, p0, p1);
+  Reduction r = Reduce(select, MachineOperatorBuilder::kFloat32Min);
+  ASSERT_TRUE(r.Changed());
+  EXPECT_THAT(r.replacement(), IsFloat32Min(p0, p1));
+}
+
+
+TEST_F(CommonOperatorReducerTest, SelectToFloat64Min) {
   Node* p0 = Parameter(0);
   Node* p1 = Parameter(1);
   Node* check = graph()->NewNode(machine()->Float64LessThan(), p0, p1);
-  Reduction r1 =
-      Reduce(graph()->NewNode(common()->Select(kMachFloat64), check, p1, p0),
-             MachineOperatorBuilder::kFloat64Max);
-  ASSERT_TRUE(r1.Changed());
-  EXPECT_THAT(r1.replacement(), IsFloat64Max(p1, p0));
-  Reduction r2 =
-      Reduce(graph()->NewNode(common()->Select(kMachFloat64), check, p0, p1),
-             MachineOperatorBuilder::kFloat64Min);
-  ASSERT_TRUE(r2.Changed());
-  EXPECT_THAT(r2.replacement(), IsFloat64Min(p0, p1));
+  Node* select =
+      graph()->NewNode(common()->Select(kMachFloat64), check, p0, p1);
+  Reduction r = Reduce(select, MachineOperatorBuilder::kFloat64Min);
+  ASSERT_TRUE(r.Changed());
+  EXPECT_THAT(r.replacement(), IsFloat64Min(p0, p1));
 }
 
 }  // namespace compiler
index d871c702525a48d36a1134c7d094214db322fa6c..f43de4a4764883d6dce186fe9d5bae620b054dc4 100644 (file)
@@ -639,6 +639,40 @@ TEST_F(InstructionSelectorTest, Int32MulHigh) {
 // Floating point operations.
 
 
+TEST_F(InstructionSelectorTest, Float32Abs) {
+  StreamBuilder m(this, kMachFloat32, kMachFloat32);
+  Node* const p0 = m.Parameter(0);
+  Node* const n = m.Float32Abs(p0);
+  m.Return(n);
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kSSEFloat32Abs, 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_TRUE(s.IsSameAsFirst(s[0]->Output()));
+  EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
+  EXPECT_EQ(kFlags_none, s[0]->flags_mode());
+}
+
+
+TEST_F(InstructionSelectorTest, Float64Abs) {
+  StreamBuilder m(this, kMachFloat64, kMachFloat64);
+  Node* const p0 = m.Parameter(0);
+  Node* const n = m.Float64Abs(p0);
+  m.Return(n);
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kSSEFloat64Abs, 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_TRUE(s.IsSameAsFirst(s[0]->Output()));
+  EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
+  EXPECT_EQ(kFlags_none, s[0]->flags_mode());
+}
+
+
 TEST_F(InstructionSelectorTest, Float64BinopArithmetic) {
   {
     StreamBuilder m(this, kMachFloat64, kMachFloat64, kMachFloat64);
index 88e7c586dddff4aa7ae2e68b0d13b79e98357050..31f55793c3f881f8c6d4c4ffc473a4431cf2def5 100644 (file)
@@ -202,12 +202,13 @@ const PureOperator kPureOperators[] = {
     PURE(TruncateFloat64ToInt32, 1, 0, 1), PURE(TruncateInt64ToInt32, 1, 0, 1),
     PURE(Float32Add, 2, 0, 1), PURE(Float32Sub, 2, 0, 1),
     PURE(Float32Mul, 2, 0, 1), PURE(Float32Div, 2, 0, 1),
-    PURE(Float32Sqrt, 1, 0, 1), PURE(Float32Equal, 2, 0, 1),
-    PURE(Float32LessThan, 2, 0, 1), PURE(Float32LessThanOrEqual, 2, 0, 1),
-    PURE(Float32Max, 2, 0, 1), PURE(Float32Min, 2, 0, 1),
-    PURE(Float64Add, 2, 0, 1), PURE(Float64Sub, 2, 0, 1),
-    PURE(Float64Mul, 2, 0, 1), PURE(Float64Div, 2, 0, 1),
-    PURE(Float64Mod, 2, 0, 1), PURE(Float64Sqrt, 1, 0, 1),
+    PURE(Float32Abs, 1, 0, 1), PURE(Float32Sqrt, 1, 0, 1),
+    PURE(Float32Equal, 2, 0, 1), PURE(Float32LessThan, 2, 0, 1),
+    PURE(Float32LessThanOrEqual, 2, 0, 1), PURE(Float32Max, 2, 0, 1),
+    PURE(Float32Min, 2, 0, 1), PURE(Float64Add, 2, 0, 1),
+    PURE(Float64Sub, 2, 0, 1), PURE(Float64Mul, 2, 0, 1),
+    PURE(Float64Div, 2, 0, 1), PURE(Float64Mod, 2, 0, 1),
+    PURE(Float64Abs, 1, 0, 1), PURE(Float64Sqrt, 1, 0, 1),
     PURE(Float64Equal, 2, 0, 1), PURE(Float64LessThan, 2, 0, 1),
     PURE(Float64LessThanOrEqual, 2, 0, 1), PURE(Float64Max, 2, 0, 1),
     PURE(Float64Min, 2, 0, 1), PURE(LoadStackPointer, 0, 0, 1),
index 5890b49b02e9de2ab75135bb6d6329cedb661053..2110802463d211d3c6d6e6da13edd20b8b24f2b8 100644 (file)
@@ -1602,6 +1602,8 @@ IS_BINOP_MATCHER(Int32MulHigh)
 IS_BINOP_MATCHER(Int32LessThan)
 IS_BINOP_MATCHER(Uint32LessThan)
 IS_BINOP_MATCHER(Uint32LessThanOrEqual)
+IS_BINOP_MATCHER(Float32Max)
+IS_BINOP_MATCHER(Float32Min)
 IS_BINOP_MATCHER(Float64Max)
 IS_BINOP_MATCHER(Float64Min)
 IS_BINOP_MATCHER(Float64Sub)
@@ -1624,6 +1626,8 @@ IS_UNOP_MATCHER(ChangeUint32ToUint64)
 IS_UNOP_MATCHER(TruncateFloat64ToFloat32)
 IS_UNOP_MATCHER(TruncateFloat64ToInt32)
 IS_UNOP_MATCHER(TruncateInt64ToInt32)
+IS_UNOP_MATCHER(Float32Abs)
+IS_UNOP_MATCHER(Float64Abs)
 IS_UNOP_MATCHER(Float64Sqrt)
 IS_UNOP_MATCHER(Float64RoundDown)
 IS_UNOP_MATCHER(Float64RoundTruncate)
index 7c306a2c9d963b13565d6b6eb2bab58f24895b58..52e4cfbf5a3ea610cd7380cb03b732a158edc14e 100644 (file)
@@ -203,12 +203,18 @@ Matcher<Node*> IsChangeUint32ToUint64(const Matcher<Node*>& input_matcher);
 Matcher<Node*> IsTruncateFloat64ToFloat32(const Matcher<Node*>& input_matcher);
 Matcher<Node*> IsTruncateFloat64ToInt32(const Matcher<Node*>& input_matcher);
 Matcher<Node*> IsTruncateInt64ToInt32(const Matcher<Node*>& input_matcher);
+Matcher<Node*> IsFloat32Max(const Matcher<Node*>& lhs_matcher,
+                            const Matcher<Node*>& rhs_matcher);
+Matcher<Node*> IsFloat32Min(const Matcher<Node*>& lhs_matcher,
+                            const Matcher<Node*>& rhs_matcher);
+Matcher<Node*> IsFloat32Abs(const Matcher<Node*>& input_matcher);
 Matcher<Node*> IsFloat64Max(const Matcher<Node*>& lhs_matcher,
                             const Matcher<Node*>& rhs_matcher);
 Matcher<Node*> IsFloat64Min(const Matcher<Node*>& lhs_matcher,
                             const Matcher<Node*>& rhs_matcher);
 Matcher<Node*> IsFloat64Sub(const Matcher<Node*>& lhs_matcher,
                             const Matcher<Node*>& rhs_matcher);
+Matcher<Node*> IsFloat64Abs(const Matcher<Node*>& input_matcher);
 Matcher<Node*> IsFloat64Sqrt(const Matcher<Node*>& input_matcher);
 Matcher<Node*> IsFloat64RoundDown(const Matcher<Node*>& input_matcher);
 Matcher<Node*> IsFloat64RoundTruncate(const Matcher<Node*>& input_matcher);
index 6d0e589e3bf04d4607229e8cbfe64d1ade73943c..226b55abdfe272814c402dcc3ff8a16859d85c42 100644 (file)
@@ -996,6 +996,40 @@ TEST_F(InstructionSelectorTest, Int32Shl4BecomesLea) {
 // Floating point operations.
 
 
+TEST_F(InstructionSelectorTest, Float32Abs) {
+  StreamBuilder m(this, kMachFloat32, kMachFloat32);
+  Node* const p0 = m.Parameter(0);
+  Node* const n = m.Float32Abs(p0);
+  m.Return(n);
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kSSEFloat32Abs, 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_TRUE(s.IsSameAsFirst(s[0]->Output()));
+  EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
+  EXPECT_EQ(kFlags_none, s[0]->flags_mode());
+}
+
+
+TEST_F(InstructionSelectorTest, Float64Abs) {
+  StreamBuilder m(this, kMachFloat64, kMachFloat64);
+  Node* const p0 = m.Parameter(0);
+  Node* const n = m.Float64Abs(p0);
+  m.Return(n);
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kSSEFloat64Abs, 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_TRUE(s.IsSameAsFirst(s[0]->Output()));
+  EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
+  EXPECT_EQ(kFlags_none, s[0]->flags_mode());
+}
+
+
 TEST_F(InstructionSelectorTest, Float64BinopArithmetic) {
   {
     StreamBuilder m(this, kMachFloat64, kMachFloat64, kMachFloat64);
@@ -1028,6 +1062,22 @@ TEST_F(InstructionSelectorTest, Float64BinopArithmetic) {
 }
 
 
+TEST_F(InstructionSelectorTest, Float32SubWithMinusZeroAndParameter) {
+  StreamBuilder m(this, kMachFloat32, kMachFloat32);
+  Node* const p0 = m.Parameter(0);
+  Node* const n = m.Float32Sub(m.Float32Constant(-0.0f), p0);
+  m.Return(n);
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kSSEFloat32Neg, 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()));
+  EXPECT_EQ(kFlags_none, s[0]->flags_mode());
+}
+
+
 TEST_F(InstructionSelectorTest, Float64SubWithMinusZeroAndParameter) {
   StreamBuilder m(this, kMachFloat64, kMachFloat64);
   Node* const p0 = m.Parameter(0);