Upgrade V8 to version 4.9.385.28

https://chromium.googlesource.com/v8/v8/+/4.9.385.28

FPIIM-449

Change-Id: I4b2e74289d4bf3667f2f3dc8aa2e541f63e26eb4
diff --git a/src/compiler/common-operator-reducer.cc b/src/compiler/common-operator-reducer.cc
index cf597ea..2334541 100644
--- a/src/compiler/common-operator-reducer.cc
+++ b/src/compiler/common-operator-reducer.cc
@@ -4,29 +4,354 @@
 
 #include "src/compiler/common-operator-reducer.h"
 
+#include <algorithm>
+
 #include "src/compiler/common-operator.h"
+#include "src/compiler/graph.h"
+#include "src/compiler/machine-operator.h"
+#include "src/compiler/node.h"
+#include "src/compiler/node-matchers.h"
+#include "src/compiler/node-properties.h"
 
 namespace v8 {
 namespace internal {
 namespace compiler {
 
+namespace {
+
+enum class Decision { kUnknown, kTrue, kFalse };
+
+Decision DecideCondition(Node* const cond) {
+  switch (cond->opcode()) {
+    case IrOpcode::kInt32Constant: {
+      Int32Matcher mcond(cond);
+      return mcond.Value() ? Decision::kTrue : Decision::kFalse;
+    }
+    case IrOpcode::kInt64Constant: {
+      Int64Matcher mcond(cond);
+      return mcond.Value() ? Decision::kTrue : Decision::kFalse;
+    }
+    case IrOpcode::kHeapConstant: {
+      HeapObjectMatcher mcond(cond);
+      return mcond.Value()->BooleanValue() ? Decision::kTrue : Decision::kFalse;
+    }
+    default:
+      return Decision::kUnknown;
+  }
+}
+
+}  // namespace
+
+
+CommonOperatorReducer::CommonOperatorReducer(Editor* editor, Graph* graph,
+                                             CommonOperatorBuilder* common,
+                                             MachineOperatorBuilder* machine)
+    : AdvancedReducer(editor),
+      graph_(graph),
+      common_(common),
+      machine_(machine),
+      dead_(graph->NewNode(common->Dead())) {}
+
+
 Reduction CommonOperatorReducer::Reduce(Node* node) {
   switch (node->opcode()) {
+    case IrOpcode::kBranch:
+      return ReduceBranch(node);
+    case IrOpcode::kMerge:
+      return ReduceMerge(node);
     case IrOpcode::kEffectPhi:
-    case IrOpcode::kPhi: {
-      int const input_count = node->InputCount();
-      if (input_count > 1) {
-        Node* const replacement = node->InputAt(0);
-        for (int i = 1; i < input_count - 1; ++i) {
-          if (node->InputAt(i) != replacement) return NoChange();
+      return ReduceEffectPhi(node);
+    case IrOpcode::kPhi:
+      return ReducePhi(node);
+    case IrOpcode::kReturn:
+      return ReduceReturn(node);
+    case IrOpcode::kSelect:
+      return ReduceSelect(node);
+    case IrOpcode::kGuard:
+      return ReduceGuard(node);
+    default:
+      break;
+  }
+  return NoChange();
+}
+
+
+Reduction CommonOperatorReducer::ReduceBranch(Node* node) {
+  DCHECK_EQ(IrOpcode::kBranch, node->opcode());
+  Node* const cond = node->InputAt(0);
+  // Swap IfTrue/IfFalse on {branch} if {cond} is a BooleanNot and use the input
+  // to BooleanNot as new condition for {branch}. Note we assume that {cond} was
+  // already properly optimized before we get here (as guaranteed by the graph
+  // reduction logic).
+  if (cond->opcode() == IrOpcode::kBooleanNot) {
+    for (Node* const use : node->uses()) {
+      switch (use->opcode()) {
+        case IrOpcode::kIfTrue:
+          NodeProperties::ChangeOp(use, common()->IfFalse());
+          break;
+        case IrOpcode::kIfFalse:
+          NodeProperties::ChangeOp(use, common()->IfTrue());
+          break;
+        default:
+          UNREACHABLE();
+      }
+    }
+    // Update the condition of {branch}. No need to mark the uses for revisit,
+    // since we tell the graph reducer that the {branch} was changed and the
+    // graph reduction logic will ensure that the uses are revisited properly.
+    node->ReplaceInput(0, cond->InputAt(0));
+    // Negate the hint for {branch}.
+    NodeProperties::ChangeOp(
+        node, common()->Branch(NegateBranchHint(BranchHintOf(node->op()))));
+    return Changed(node);
+  }
+  Decision const decision = DecideCondition(cond);
+  if (decision == Decision::kUnknown) return NoChange();
+  Node* const control = node->InputAt(1);
+  for (Node* const use : node->uses()) {
+    switch (use->opcode()) {
+      case IrOpcode::kIfTrue:
+        Replace(use, (decision == Decision::kTrue) ? control : dead());
+        break;
+      case IrOpcode::kIfFalse:
+        Replace(use, (decision == Decision::kFalse) ? control : dead());
+        break;
+      default:
+        UNREACHABLE();
+    }
+  }
+  return Replace(dead());
+}
+
+
+Reduction CommonOperatorReducer::ReduceMerge(Node* node) {
+  DCHECK_EQ(IrOpcode::kMerge, node->opcode());
+  //
+  // Check if this is a merge that belongs to an unused diamond, which means
+  // that:
+  //
+  //  a) the {Merge} has no {Phi} or {EffectPhi} uses, and
+  //  b) the {Merge} has two inputs, one {IfTrue} and one {IfFalse}, which are
+  //     both owned by the Merge, and
+  //  c) and the {IfTrue} and {IfFalse} nodes point to the same {Branch}.
+  //
+  if (node->InputCount() == 2) {
+    for (Node* const use : node->uses()) {
+      if (IrOpcode::IsPhiOpcode(use->opcode())) return NoChange();
+    }
+    Node* if_true = node->InputAt(0);
+    Node* if_false = node->InputAt(1);
+    if (if_true->opcode() != IrOpcode::kIfTrue) std::swap(if_true, if_false);
+    if (if_true->opcode() == IrOpcode::kIfTrue &&
+        if_false->opcode() == IrOpcode::kIfFalse &&
+        if_true->InputAt(0) == if_false->InputAt(0) && if_true->OwnedBy(node) &&
+        if_false->OwnedBy(node)) {
+      Node* const branch = if_true->InputAt(0);
+      DCHECK_EQ(IrOpcode::kBranch, branch->opcode());
+      DCHECK(branch->OwnedBy(if_true, if_false));
+      Node* const control = branch->InputAt(1);
+      // Mark the {branch} as {Dead}.
+      branch->TrimInputCount(0);
+      NodeProperties::ChangeOp(branch, common()->Dead());
+      return Replace(control);
+    }
+  }
+  return NoChange();
+}
+
+
+Reduction CommonOperatorReducer::ReduceEffectPhi(Node* node) {
+  DCHECK_EQ(IrOpcode::kEffectPhi, node->opcode());
+  int const input_count = node->InputCount() - 1;
+  DCHECK_LE(1, input_count);
+  Node* const merge = node->InputAt(input_count);
+  DCHECK(IrOpcode::IsMergeOpcode(merge->opcode()));
+  DCHECK_EQ(input_count, merge->InputCount());
+  Node* const effect = node->InputAt(0);
+  DCHECK_NE(node, effect);
+  for (int i = 1; i < input_count; ++i) {
+    Node* const input = node->InputAt(i);
+    if (input == node) {
+      // Ignore redundant inputs.
+      DCHECK_EQ(IrOpcode::kLoop, merge->opcode());
+      continue;
+    }
+    if (input != effect) return NoChange();
+  }
+  // We might now be able to further reduce the {merge} node.
+  Revisit(merge);
+  return Replace(effect);
+}
+
+
+Reduction CommonOperatorReducer::ReducePhi(Node* node) {
+  DCHECK_EQ(IrOpcode::kPhi, node->opcode());
+  int const input_count = node->InputCount() - 1;
+  DCHECK_LE(1, input_count);
+  Node* const merge = node->InputAt(input_count);
+  DCHECK(IrOpcode::IsMergeOpcode(merge->opcode()));
+  DCHECK_EQ(input_count, merge->InputCount());
+  if (input_count == 2) {
+    Node* vtrue = node->InputAt(0);
+    Node* vfalse = node->InputAt(1);
+    Node* if_true = merge->InputAt(0);
+    Node* if_false = merge->InputAt(1);
+    if (if_true->opcode() != IrOpcode::kIfTrue) {
+      std::swap(if_true, if_false);
+      std::swap(vtrue, vfalse);
+    }
+    if (if_true->opcode() == IrOpcode::kIfTrue &&
+        if_false->opcode() == IrOpcode::kIfFalse &&
+        if_true->InputAt(0) == if_false->InputAt(0)) {
+      Node* const branch = if_true->InputAt(0);
+      // Check that the branch is not dead already.
+      if (branch->opcode() != IrOpcode::kBranch) return NoChange();
+      Node* const cond = branch->InputAt(0);
+      if (cond->opcode() == IrOpcode::kFloat32LessThan) {
+        Float32BinopMatcher mcond(cond);
+        if (mcond.left().Is(0.0) && mcond.right().Equals(vtrue) &&
+            vfalse->opcode() == IrOpcode::kFloat32Sub) {
+          Float32BinopMatcher mvfalse(vfalse);
+          if (mvfalse.left().IsZero() && mvfalse.right().Equals(vtrue)) {
+            // We might now be able to further reduce the {merge} node.
+            Revisit(merge);
+            return Change(node, machine()->Float32Abs(), vtrue);
+          }
         }
-        return Replace(replacement);
+        if (mcond.left().Equals(vtrue) && mcond.right().Equals(vfalse) &&
+            machine()->Float32Min().IsSupported()) {
+          // We might now be able to further reduce the {merge} node.
+          Revisit(merge);
+          return Change(node, machine()->Float32Min().op(), vtrue, vfalse);
+        } else if (mcond.left().Equals(vfalse) && mcond.right().Equals(vtrue) &&
+                   machine()->Float32Max().IsSupported()) {
+          // We might now be able to further reduce the {merge} node.
+          Revisit(merge);
+          return Change(node, machine()->Float32Max().op(), 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) {
+          Float64BinopMatcher mvfalse(vfalse);
+          if (mvfalse.left().IsZero() && mvfalse.right().Equals(vtrue)) {
+            // We might now be able to further reduce the {merge} node.
+            Revisit(merge);
+            return Change(node, machine()->Float64Abs(), vtrue);
+          }
+        }
+        if (mcond.left().Equals(vtrue) && mcond.right().Equals(vfalse) &&
+            machine()->Float64Min().IsSupported()) {
+          // We might now be able to further reduce the {merge} node.
+          Revisit(merge);
+          return Change(node, machine()->Float64Min().op(), vtrue, vfalse);
+        } else if (mcond.left().Equals(vfalse) && mcond.right().Equals(vtrue) &&
+                   machine()->Float64Max().IsSupported()) {
+          // We might now be able to further reduce the {merge} node.
+          Revisit(merge);
+          return Change(node, machine()->Float64Max().op(), vtrue, vfalse);
+        }
+      }
+    }
+  }
+  Node* const value = node->InputAt(0);
+  DCHECK_NE(node, value);
+  for (int i = 1; i < input_count; ++i) {
+    Node* const input = node->InputAt(i);
+    if (input == node) {
+      // Ignore redundant inputs.
+      DCHECK_EQ(IrOpcode::kLoop, merge->opcode());
+      continue;
+    }
+    if (input != value) return NoChange();
+  }
+  // We might now be able to further reduce the {merge} node.
+  Revisit(merge);
+  return Replace(value);
+}
+
+
+Reduction CommonOperatorReducer::ReduceReturn(Node* node) {
+  DCHECK_EQ(IrOpcode::kReturn, node->opcode());
+  Node* const value = node->InputAt(0);
+  Node* const effect = node->InputAt(1);
+  Node* const control = node->InputAt(2);
+  if (value->opcode() == IrOpcode::kPhi &&
+      NodeProperties::GetControlInput(value) == control &&
+      effect->opcode() == IrOpcode::kEffectPhi &&
+      NodeProperties::GetControlInput(effect) == control &&
+      control->opcode() == IrOpcode::kMerge) {
+    int const control_input_count = control->InputCount();
+    DCHECK_NE(0, control_input_count);
+    DCHECK_EQ(control_input_count, value->InputCount() - 1);
+    DCHECK_EQ(control_input_count, effect->InputCount() - 1);
+    DCHECK_EQ(IrOpcode::kEnd, graph()->end()->opcode());
+    DCHECK_NE(0, graph()->end()->InputCount());
+    for (int i = 0; i < control_input_count; ++i) {
+      // Create a new {Return} and connect it to {end}. We don't need to mark
+      // {end} as revisit, because we mark {node} as {Dead} below, which was
+      // previously connected to {end}, so we know for sure that at some point
+      // the reducer logic will visit {end} again.
+      Node* ret = graph()->NewNode(common()->Return(), value->InputAt(i),
+                                   effect->InputAt(i), control->InputAt(i));
+      NodeProperties::MergeControlToEnd(graph(), common(), ret);
+    }
+    // Mark the merge {control} and return {node} as {dead}.
+    Replace(control, dead());
+    return Replace(dead());
+  }
+  return NoChange();
+}
+
+
+Reduction CommonOperatorReducer::ReduceSelect(Node* node) {
+  DCHECK_EQ(IrOpcode::kSelect, node->opcode());
+  Node* const cond = node->InputAt(0);
+  Node* const vtrue = node->InputAt(1);
+  Node* const vfalse = node->InputAt(2);
+  if (vtrue == vfalse) return Replace(vtrue);
+  switch (DecideCondition(cond)) {
+    case Decision::kTrue:
+      return Replace(vtrue);
+    case Decision::kFalse:
+      return Replace(vfalse);
+    case Decision::kUnknown:
+      break;
+  }
+  switch (cond->opcode()) {
+    case IrOpcode::kFloat32LessThan: {
+      Float32BinopMatcher mcond(cond);
+      if (mcond.left().Is(0.0) && mcond.right().Equals(vtrue) &&
+          vfalse->opcode() == IrOpcode::kFloat32Sub) {
+        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()->Float32Min().IsSupported()) {
+        return Change(node, machine()->Float32Min().op(), vtrue, vfalse);
+      } else if (mcond.left().Equals(vfalse) && mcond.right().Equals(vtrue) &&
+                 machine()->Float32Max().IsSupported()) {
+        return Change(node, machine()->Float32Max().op(), vtrue, vfalse);
       }
       break;
     }
-    case IrOpcode::kSelect: {
-      if (node->InputAt(1) == node->InputAt(2)) {
-        return Replace(node->InputAt(1));
+    case IrOpcode::kFloat64LessThan: {
+      Float64BinopMatcher mcond(cond);
+      if (mcond.left().Is(0.0) && mcond.right().Equals(vtrue) &&
+          vfalse->opcode() == IrOpcode::kFloat64Sub) {
+        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()->Float64Min().IsSupported()) {
+        return Change(node, machine()->Float64Min().op(), vtrue, vfalse);
+      } else if (mcond.left().Equals(vfalse) && mcond.right().Equals(vtrue) &&
+                 machine()->Float64Max().IsSupported()) {
+        return Change(node, machine()->Float64Max().op(), vtrue, vfalse);
       }
       break;
     }
@@ -36,6 +361,35 @@
   return NoChange();
 }
 
+
+Reduction CommonOperatorReducer::ReduceGuard(Node* node) {
+  DCHECK_EQ(IrOpcode::kGuard, node->opcode());
+  Node* const input = NodeProperties::GetValueInput(node, 0);
+  Type* const input_type = NodeProperties::GetTypeOrAny(input);
+  Type* const guard_type = OpParameter<Type*>(node);
+  if (input_type->Is(guard_type)) return Replace(input);
+  return NoChange();
+}
+
+
+Reduction CommonOperatorReducer::Change(Node* node, Operator const* op,
+                                        Node* a) {
+  node->ReplaceInput(0, a);
+  node->TrimInputCount(1);
+  NodeProperties::ChangeOp(node, op);
+  return Changed(node);
+}
+
+
+Reduction CommonOperatorReducer::Change(Node* node, Operator const* op, Node* a,
+                                        Node* b) {
+  node->ReplaceInput(0, a);
+  node->ReplaceInput(1, b);
+  node->TrimInputCount(2);
+  NodeProperties::ChangeOp(node, op);
+  return Changed(node);
+}
+
 }  // namespace compiler
 }  // namespace internal
 }  // namespace v8