[turbofan] Add new JSIntrinsicsLowering reducer.
authorbmeurer <bmeurer@chromium.org>
Mon, 26 Jan 2015 09:05:47 +0000 (01:05 -0800)
committerCommit bot <commit-bot@chromium.org>
Mon, 26 Jan 2015 09:06:03 +0000 (09:06 +0000)
The lowering of intrinsics is therefore now decoupled from the general
inlining logic.

TEST=cctest,unittests
R=svenpanne@chromium.org

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

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

17 files changed:
BUILD.gn
src/compiler/js-inlining.cc
src/compiler/js-inlining.h
src/compiler/js-intrinsic-builder.cc [deleted file]
src/compiler/js-intrinsic-builder.h [deleted file]
src/compiler/js-intrinsic-lowering.cc [new file with mode: 0644]
src/compiler/js-intrinsic-lowering.h [new file with mode: 0644]
src/compiler/pipeline.cc
src/compiler/simplified-lowering.cc
src/compiler/typer.cc
src/flag-definitions.h
test/cctest/compiler/test-run-intrinsics.cc
test/unittests/compiler/js-intrinsic-lowering-unittest.cc [new file with mode: 0644]
test/unittests/compiler/node-test-utils.cc
test/unittests/compiler/node-test-utils.h
test/unittests/unittests.gyp
tools/gyp/v8.gyp

index f929a91..6510b92 100644 (file)
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -561,8 +561,8 @@ source_set("v8_base") {
     "src/compiler/js-graph.h",
     "src/compiler/js-inlining.cc",
     "src/compiler/js-inlining.h",
-    "src/compiler/js-intrinsic-builder.cc",
-    "src/compiler/js-intrinsic-builder.h",
+    "src/compiler/js-intrinsic-lowering.cc",
+    "src/compiler/js-intrinsic-lowering.h",
     "src/compiler/js-operator.cc",
     "src/compiler/js-operator.h",
     "src/compiler/js-typed-lowering.cc",
index 040c721..d68c31a 100644 (file)
@@ -10,7 +10,6 @@
 #include "src/compiler/graph-inl.h"
 #include "src/compiler/graph-visualizer.h"
 #include "src/compiler/js-inlining.h"
-#include "src/compiler/js-intrinsic-builder.h"
 #include "src/compiler/js-operator.h"
 #include "src/compiler/node-aux-data-inl.h"
 #include "src/compiler/node-matchers.h"
@@ -36,11 +35,6 @@ class InlinerVisitor : public NullNodeVisitor {
       case IrOpcode::kJSCallFunction:
         inliner_->TryInlineJSCall(node);
         break;
-      case IrOpcode::kJSCallRuntime:
-        if (FLAG_turbo_inlining_intrinsics) {
-          inliner_->TryInlineRuntimeCall(node);
-        }
-        break;
       default:
         break;
     }
@@ -418,70 +412,6 @@ void JSInliner::TryInlineJSCall(Node* call_node) {
   inlinee.InlineAtCall(jsgraph_, call_node);
 }
 
-
-class JSCallRuntimeAccessor {
- public:
-  explicit JSCallRuntimeAccessor(Node* call) : call_(call) {
-    DCHECK_EQ(IrOpcode::kJSCallRuntime, call->opcode());
-  }
-
-  Node* formal_argument(size_t index) {
-    DCHECK(index < formal_arguments());
-    return call_->InputAt(static_cast<int>(index));
-  }
-
-  size_t formal_arguments() {
-    size_t value_inputs = call_->op()->ValueInputCount();
-    return value_inputs;
-  }
-
-  Node* frame_state() const {
-    return NodeProperties::GetFrameStateInput(call_);
-  }
-  Node* context() const { return NodeProperties::GetContextInput(call_); }
-  Node* control() const { return NodeProperties::GetControlInput(call_); }
-  Node* effect() const { return NodeProperties::GetEffectInput(call_); }
-
-  const Runtime::Function* function() const {
-    return Runtime::FunctionForId(CallRuntimeParametersOf(call_->op()).id());
-  }
-
-  NodeVector inputs(Zone* zone) const {
-    NodeVector inputs(zone);
-    for (Node* const node : call_->inputs()) {
-      inputs.push_back(node);
-    }
-    return inputs;
-  }
-
- private:
-  Node* call_;
-};
-
-
-void JSInliner::TryInlineRuntimeCall(Node* call_node) {
-  JSCallRuntimeAccessor call(call_node);
-  const Runtime::Function* f = call.function();
-
-  if (f->intrinsic_type != Runtime::IntrinsicType::INLINE) {
-    return;
-  }
-
-  JSIntrinsicBuilder intrinsic_builder(jsgraph_);
-
-  ResultAndEffect r = intrinsic_builder.BuildGraphFor(
-      f->function_id, call.inputs(jsgraph_->zone()));
-
-  if (r.first != NULL) {
-    if (FLAG_trace_turbo_inlining) {
-      PrintF("Inlining %s into %s\n", f->name,
-             info_->shared_info()->DebugName()->ToCString().get());
-    }
-    NodeProperties::ReplaceWithValue(call_node, r.first, r.second);
-    call_node->RemoveAllInputs();
-    DCHECK_EQ(0, call_node->UseCount());
-  }
-}
-}
-}
-}  // namespace v8::internal::compiler
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
index eef29d6..acaa4a7 100644 (file)
@@ -21,7 +21,6 @@ class JSInliner {
 
   void Inline();
   void TryInlineJSCall(Node* node);
-  void TryInlineRuntimeCall(Node* node);
 
  private:
   friend class InlinerVisitor;
diff --git a/src/compiler/js-intrinsic-builder.cc b/src/compiler/js-intrinsic-builder.cc
deleted file mode 100644 (file)
index 80b6968..0000000
+++ /dev/null
@@ -1,140 +0,0 @@
-// Copyright 2014 the V8 project authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "src/compiler/access-builder.h"
-#include "src/compiler/common-operator.h"
-#include "src/compiler/diamond.h"
-#include "src/compiler/js-intrinsic-builder.h"
-#include "src/compiler/js-operator.h"
-#include "src/compiler/simplified-operator.h"
-
-
-namespace v8 {
-namespace internal {
-namespace compiler {
-
-ResultAndEffect JSIntrinsicBuilder::BuildGraphFor(Runtime::FunctionId id,
-                                                  const NodeVector& arguments) {
-  switch (id) {
-    case Runtime::kInlineIsSmi:
-      return BuildGraphFor_IsSmi(arguments);
-    case Runtime::kInlineIsNonNegativeSmi:
-      return BuildGraphFor_IsNonNegativeSmi(arguments);
-    case Runtime::kInlineIsArray:
-      return BuildMapCheck(arguments[0], arguments[2], JS_ARRAY_TYPE);
-    case Runtime::kInlineIsRegExp:
-      return BuildMapCheck(arguments[0], arguments[2], JS_REGEXP_TYPE);
-    case Runtime::kInlineIsFunction:
-      return BuildMapCheck(arguments[0], arguments[2], JS_FUNCTION_TYPE);
-    case Runtime::kInlineValueOf:
-      return BuildGraphFor_ValueOf(arguments);
-    default:
-      break;
-  }
-  return ResultAndEffect();
-}
-
-ResultAndEffect JSIntrinsicBuilder::BuildGraphFor_IsSmi(
-    const NodeVector& arguments) {
-  Node* object = arguments[0];
-  SimplifiedOperatorBuilder simplified(jsgraph_->zone());
-  Node* condition = graph()->NewNode(simplified.ObjectIsSmi(), object);
-
-  return ResultAndEffect(condition, arguments[2]);
-}
-
-
-ResultAndEffect JSIntrinsicBuilder::BuildGraphFor_IsNonNegativeSmi(
-    const NodeVector& arguments) {
-  Node* object = arguments[0];
-  SimplifiedOperatorBuilder simplified(jsgraph_->zone());
-  Node* condition =
-      graph()->NewNode(simplified.ObjectIsNonNegativeSmi(), object);
-
-  return ResultAndEffect(condition, arguments[2]);
-}
-
-
-/*
- * if (_isSmi(object)) {
- *   return false
- * } else {
- *   return %_GetMapInstanceType(object) == map_type
- * }
- */
-ResultAndEffect JSIntrinsicBuilder::BuildMapCheck(Node* object, Node* effect,
-                                                  InstanceType map_type) {
-  SimplifiedOperatorBuilder simplified(jsgraph_->zone());
-
-  Node* is_smi = graph()->NewNode(simplified.ObjectIsSmi(), object);
-  Diamond d(graph(), common(), is_smi);
-
-  Node* map = graph()->NewNode(simplified.LoadField(AccessBuilder::ForMap()),
-                               object, effect, d.if_false);
-
-  Node* instance_type = graph()->NewNode(
-      simplified.LoadField(AccessBuilder::ForMapInstanceType()), map, map,
-      d.if_false);
-
-  Node* has_map_type =
-      graph()->NewNode(jsgraph_->machine()->Word32Equal(), instance_type,
-                       jsgraph_->Int32Constant(map_type));
-
-  Node* phi = d.Phi(static_cast<MachineType>(kTypeBool | kRepTagged),
-                    jsgraph_->FalseConstant(), has_map_type);
-
-  Node* ephi = d.EffectPhi(effect, instance_type);
-
-  return ResultAndEffect(phi, ephi);
-}
-
-
-/*
- * if (%_isSmi(object)) {
- *   return object;
- * } else if (%_GetMapInstanceType(object) == JS_VALUE_TYPE) {
- *   return %_LoadValueField(object);
- * } else {
- *   return object;
- * }
- */
-ResultAndEffect JSIntrinsicBuilder::BuildGraphFor_ValueOf(
-    const NodeVector& arguments) {
-  Node* object = arguments[0];
-  Node* effect = arguments[2];
-  SimplifiedOperatorBuilder simplified(jsgraph_->zone());
-
-  Node* is_smi = graph()->NewNode(simplified.ObjectIsSmi(), object);
-
-  Diamond if_is_smi(graph(), common(), is_smi);
-
-  Node* map = graph()->NewNode(simplified.LoadField(AccessBuilder::ForMap()),
-                               object, effect, if_is_smi.if_false);
-
-  Node* instance_type = graph()->NewNode(
-      simplified.LoadField(AccessBuilder::ForMapInstanceType()), map, map,
-      if_is_smi.if_false);
-
-  Node* is_value =
-      graph()->NewNode(jsgraph_->machine()->Word32Equal(), instance_type,
-                       jsgraph_->Constant(JS_VALUE_TYPE));
-
-  Diamond if_is_value(graph(), common(), is_value);
-  if_is_value.Nest(if_is_smi, false);
-
-  Node* value =
-      graph()->NewNode(simplified.LoadField(AccessBuilder::ForValue()), object,
-                       instance_type, if_is_value.if_true);
-
-  Node* phi_is_value = if_is_value.Phi(kTypeAny, value, object);
-
-  Node* phi = if_is_smi.Phi(kTypeAny, object, phi_is_value);
-
-  Node* ephi = if_is_smi.EffectPhi(effect, instance_type);
-
-  return ResultAndEffect(phi, ephi);
-}
-}
-}
-}  // namespace v8::internal::compiler
diff --git a/src/compiler/js-intrinsic-builder.h b/src/compiler/js-intrinsic-builder.h
deleted file mode 100644 (file)
index 9336be6..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright 2014 the V8 project authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef V8_COMPILER_JS_INTRINSIC_BUILDER_H_
-#define V8_COMPILER_JS_INTRINSIC_BUILDER_H_
-
-#include "src/compiler/js-graph.h"
-#include "src/v8.h"
-
-namespace v8 {
-namespace internal {
-namespace compiler {
-
-typedef std::pair<Node*, Node*> ResultAndEffect;
-
-class JSIntrinsicBuilder {
- public:
-  explicit JSIntrinsicBuilder(JSGraph* jsgraph) : jsgraph_(jsgraph) {}
-
-  ResultAndEffect BuildGraphFor(Runtime::FunctionId id,
-                                const NodeVector& arguments);
-
- private:
-  ResultAndEffect BuildMapCheck(Node* object, Node* effect,
-                                InstanceType map_type);
-  ResultAndEffect BuildGraphFor_IsSmi(const NodeVector& arguments);
-  ResultAndEffect BuildGraphFor_IsNonNegativeSmi(const NodeVector& arguments);
-  ResultAndEffect BuildGraphFor_ValueOf(const NodeVector& arguments);
-
-
-  Graph* graph() const { return jsgraph_->graph(); }
-  CommonOperatorBuilder* common() const { return jsgraph_->common(); }
-  JSGraph* jsgraph_;
-};
-}
-}
-}  // namespace v8::internal::compiler
-
-#endif  // V8_COMPILER_JS_INTRINSIC_BUILDER_H_
diff --git a/src/compiler/js-intrinsic-lowering.cc b/src/compiler/js-intrinsic-lowering.cc
new file mode 100644 (file)
index 0000000..99def30
--- /dev/null
@@ -0,0 +1,194 @@
+// Copyright 2015 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/compiler/js-intrinsic-lowering.h"
+
+#include "src/compiler/access-builder.h"
+#include "src/compiler/js-graph.h"
+#include "src/compiler/node-properties-inl.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+JSIntrinsicLowering::JSIntrinsicLowering(JSGraph* jsgraph)
+    : jsgraph_(jsgraph), simplified_(jsgraph->zone()) {}
+
+
+Reduction JSIntrinsicLowering::Reduce(Node* node) {
+  if (node->opcode() != IrOpcode::kJSCallRuntime) return NoChange();
+  const Runtime::Function* const f =
+      Runtime::FunctionForId(CallRuntimeParametersOf(node->op()).id());
+  if (f->intrinsic_type != Runtime::IntrinsicType::INLINE) return NoChange();
+  switch (f->function_id) {
+    case Runtime::kInlineIsSmi:
+      return ReduceInlineIsSmi(node);
+    case Runtime::kInlineIsNonNegativeSmi:
+      return ReduceInlineIsNonNegativeSmi(node);
+    case Runtime::kInlineIsArray:
+      return ReduceInlineIsInstanceType(node, JS_ARRAY_TYPE);
+    case Runtime::kInlineIsFunction:
+      return ReduceInlineIsInstanceType(node, JS_FUNCTION_TYPE);
+    case Runtime::kInlineIsRegExp:
+      return ReduceInlineIsInstanceType(node, JS_REGEXP_TYPE);
+    case Runtime::kInlineValueOf:
+      return ReduceInlineValueOf(node);
+    default:
+      break;
+  }
+  return NoChange();
+}
+
+
+Reduction JSIntrinsicLowering::ReduceInlineIsSmi(Node* node) {
+  return Change(node, simplified()->ObjectIsSmi());
+}
+
+
+Reduction JSIntrinsicLowering::ReduceInlineIsNonNegativeSmi(Node* node) {
+  return Change(node, simplified()->ObjectIsNonNegativeSmi());
+}
+
+
+Reduction JSIntrinsicLowering::ReduceInlineIsInstanceType(
+    Node* node, InstanceType instance_type) {
+  // if (%_IsSmi(value)) {
+  //   return false;
+  // } else {
+  //   return %_GetInstanceType(%_GetMap(value)) == instance_type;
+  // }
+  MachineType const type = static_cast<MachineType>(kTypeBool | kRepTagged);
+
+  Node* value = NodeProperties::GetValueInput(node, 0);
+  Node* effect = NodeProperties::GetEffectInput(node);
+  Node* control = NodeProperties::GetControlInput(node);
+
+  Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), value);
+  Node* branch = graph()->NewNode(common()->Branch(), check, control);
+
+  Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
+  Node* etrue = effect;
+  Node* vtrue = jsgraph()->FalseConstant();
+
+  Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
+  Node* efalse = graph()->NewNode(
+      simplified()->LoadField(AccessBuilder::ForMapInstanceType()),
+      graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), value,
+                       effect, if_false),
+      effect, if_false);
+  Node* vfalse = graph()->NewNode(machine()->Word32Equal(), efalse,
+                                  jsgraph()->Int32Constant(instance_type));
+
+  Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
+
+  // Replace all effect uses of {node} with the {ephi}.
+  Node* ephi = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, merge);
+  NodeProperties::ReplaceWithValue(node, node, ephi);
+
+  // Turn the {node} into a Phi.
+  return Change(node, common()->Phi(type, 2), vtrue, vfalse, merge);
+}
+
+
+Reduction JSIntrinsicLowering::ReduceInlineValueOf(Node* node) {
+  // if (%_IsSmi(value)) {
+  //   return value;
+  // } else if (%_GetInstanceType(%_GetMap(value)) == JS_VALUE_TYPE) {
+  //   return %_GetValue(value);
+  // } else {
+  //   return value;
+  // }
+  const Operator* const merge_op = common()->Merge(2);
+  const Operator* const ephi_op = common()->EffectPhi(2);
+  const Operator* const phi_op = common()->Phi(kMachAnyTagged, 2);
+
+  Node* value = NodeProperties::GetValueInput(node, 0);
+  Node* effect = NodeProperties::GetEffectInput(node);
+  Node* control = NodeProperties::GetControlInput(node);
+
+  Node* check0 = graph()->NewNode(simplified()->ObjectIsSmi(), value);
+  Node* branch0 = graph()->NewNode(common()->Branch(), check0, control);
+
+  Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
+  Node* etrue0 = effect;
+  Node* vtrue0 = value;
+
+  Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
+  Node* efalse0;
+  Node* vfalse0;
+  {
+    Node* check1 = graph()->NewNode(
+        machine()->Word32Equal(),
+        graph()->NewNode(
+            simplified()->LoadField(AccessBuilder::ForMapInstanceType()),
+            graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
+                             value, effect, if_false0),
+            effect, if_false0),
+        jsgraph()->Int32Constant(JS_VALUE_TYPE));
+    Node* branch1 = graph()->NewNode(common()->Branch(), check1, if_false0);
+
+    Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
+    Node* etrue1 =
+        graph()->NewNode(simplified()->LoadField(AccessBuilder::ForValue()),
+                         value, effect, if_true1);
+    Node* vtrue1 = etrue1;
+
+    Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
+    Node* efalse1 = effect;
+    Node* vfalse1 = value;
+
+    Node* merge1 = graph()->NewNode(merge_op, if_true1, if_false1);
+    efalse0 = graph()->NewNode(ephi_op, etrue1, efalse1, merge1);
+    vfalse0 = graph()->NewNode(phi_op, vtrue1, vfalse1, merge1);
+  }
+
+  Node* merge0 = graph()->NewNode(merge_op, if_true0, if_false0);
+
+
+  // Replace all effect uses of {node} with the {ephi0}.
+  Node* ephi0 = graph()->NewNode(ephi_op, etrue0, efalse0, merge0);
+  NodeProperties::ReplaceWithValue(node, node, ephi0);
+
+  // Turn the {node} into a Phi.
+  return Change(node, phi_op, vtrue0, vfalse0, merge0);
+}
+
+
+Reduction JSIntrinsicLowering::Change(Node* node, const Operator* op) {
+  // Remove the effects from the node and update its effect usages.
+  NodeProperties::ReplaceWithValue(node, node);
+  // Remove the inputs corresponding to context, effect and control.
+  NodeProperties::RemoveNonValueInputs(node);
+  // Finally update the operator to the new one.
+  node->set_op(op);
+  return Changed(node);
+}
+
+
+Reduction JSIntrinsicLowering::Change(Node* node, const Operator* op, Node* a,
+                                      Node* b, Node* c) {
+  node->set_op(op);
+  node->ReplaceInput(0, a);
+  node->ReplaceInput(1, b);
+  node->ReplaceInput(2, c);
+  node->TrimInputCount(3);
+  return Changed(node);
+}
+
+
+Graph* JSIntrinsicLowering::graph() const { return jsgraph()->graph(); }
+
+
+CommonOperatorBuilder* JSIntrinsicLowering::common() const {
+  return jsgraph()->common();
+}
+
+
+MachineOperatorBuilder* JSIntrinsicLowering::machine() const {
+  return jsgraph()->machine();
+}
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
diff --git a/src/compiler/js-intrinsic-lowering.h b/src/compiler/js-intrinsic-lowering.h
new file mode 100644 (file)
index 0000000..bc188ca
--- /dev/null
@@ -0,0 +1,52 @@
+// Copyright 2015 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef V8_COMPILER_JS_INTRINSIC_LOWERING_H_
+#define V8_COMPILER_JS_INTRINSIC_LOWERING_H_
+
+#include "src/compiler/graph-reducer.h"
+#include "src/compiler/simplified-operator.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+// Forward declarations.
+class CommonOperatorBuilder;
+class JSGraph;
+class MachineOperatorBuilder;
+
+
+// Lowers certain JS-level runtime calls.
+class JSIntrinsicLowering FINAL : public Reducer {
+ public:
+  explicit JSIntrinsicLowering(JSGraph* jsgraph);
+  ~JSIntrinsicLowering() FINAL {}
+
+  Reduction Reduce(Node* node) FINAL;
+
+ private:
+  Reduction ReduceInlineIsSmi(Node* node);
+  Reduction ReduceInlineIsNonNegativeSmi(Node* node);
+  Reduction ReduceInlineIsInstanceType(Node* node, InstanceType instance_type);
+  Reduction ReduceInlineValueOf(Node* node);
+
+  Reduction Change(Node* node, const Operator* op);
+  Reduction Change(Node* node, const Operator* op, Node* a, Node* b, Node* c);
+
+  Graph* graph() const;
+  JSGraph* jsgraph() const { return jsgraph_; }
+  CommonOperatorBuilder* common() const;
+  MachineOperatorBuilder* machine() const;
+  SimplifiedOperatorBuilder* simplified() { return &simplified_; }
+
+  JSGraph* jsgraph_;
+  SimplifiedOperatorBuilder simplified_;
+};
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
+
+#endif  // V8_COMPILER_JS_INTRINSIC_LOWERING_H_
index 218b067..ef0144c 100644 (file)
@@ -24,6 +24,7 @@
 #include "src/compiler/js-context-specialization.h"
 #include "src/compiler/js-generic-lowering.h"
 #include "src/compiler/js-inlining.h"
+#include "src/compiler/js-intrinsic-lowering.h"
 #include "src/compiler/js-typed-lowering.h"
 #include "src/compiler/jump-threading.h"
 #include "src/compiler/load-elimination.h"
@@ -428,12 +429,14 @@ struct TypedLoweringPhase {
     LoadElimination load_elimination;
     JSBuiltinReducer builtin_reducer(data->jsgraph());
     JSTypedLowering typed_lowering(data->jsgraph(), temp_zone);
+    JSIntrinsicLowering intrinsic_lowering(data->jsgraph());
     SimplifiedOperatorReducer simple_reducer(data->jsgraph());
     CommonOperatorReducer common_reducer;
     GraphReducer graph_reducer(data->graph(), temp_zone);
     graph_reducer.AddReducer(&vn_reducer);
     graph_reducer.AddReducer(&builtin_reducer);
     graph_reducer.AddReducer(&typed_lowering);
+    graph_reducer.AddReducer(&intrinsic_lowering);
     graph_reducer.AddReducer(&load_elimination);
     graph_reducer.AddReducer(&simple_reducer);
     graph_reducer.AddReducer(&common_reducer);
index e334d1f..9b48ff7 100644 (file)
@@ -854,10 +854,10 @@ class RepresentationSelector {
         if (lower()) {
           Node* is_tagged = jsgraph_->graph()->NewNode(
               jsgraph_->machine()->WordAnd(), node->InputAt(0),
-              jsgraph_->Int32Constant(static_cast<int>(kSmiTagMask)));
+              jsgraph_->IntPtrConstant(kSmiTagMask));
           Node* is_smi = jsgraph_->graph()->NewNode(
               jsgraph_->machine()->WordEqual(), is_tagged,
-              jsgraph_->Int32Constant(kSmiTag));
+              jsgraph_->IntPtrConstant(kSmiTag));
           DeferReplacement(node, is_smi);
         }
         break;
@@ -868,13 +868,13 @@ class RepresentationSelector {
         if (lower()) {
           Node* is_tagged = jsgraph_->graph()->NewNode(
               jsgraph_->machine()->WordAnd(), node->InputAt(0),
-              jsgraph_->Int32Constant(static_cast<int>(kSmiTagMask)));
+              jsgraph_->IntPtrConstant(kSmiTagMask));
           Node* is_smi = jsgraph_->graph()->NewNode(
               jsgraph_->machine()->WordEqual(), is_tagged,
-              jsgraph_->Int32Constant(kSmiTag));
+              jsgraph_->IntPtrConstant(kSmiTag));
           Node* is_non_neg = jsgraph_->graph()->NewNode(
               jsgraph_->machine()->IntLessThanOrEqual(),
-              jsgraph_->Int32Constant(0), node->InputAt(0));
+              jsgraph_->IntPtrConstant(0), node->InputAt(0));
           Node* is_non_neg_smi = jsgraph_->graph()->NewNode(
               jsgraph_->machine()->Word32And(), is_smi, is_non_neg);
           DeferReplacement(node, is_non_neg_smi);
index 4b3a883..976a1b6 100644 (file)
@@ -1442,6 +1442,16 @@ Bounds Typer::Visitor::TypeJSCallFunction(Node* node) {
 
 
 Bounds Typer::Visitor::TypeJSCallRuntime(Node* node) {
+  switch (CallRuntimeParametersOf(node->op()).id()) {
+    case Runtime::kInlineIsSmi:
+    case Runtime::kInlineIsNonNegativeSmi:
+    case Runtime::kInlineIsArray:
+    case Runtime::kInlineIsFunction:
+    case Runtime::kInlineIsRegExp:
+      return Bounds(Type::None(zone()), Type::Boolean(zone()));
+    default:
+      break;
+  }
   return Bounds::Unbounded(zone());
 }
 
index d633426..dea3720 100644 (file)
@@ -403,11 +403,8 @@ DEFINE_BOOL(context_specialization, false,
             "enable context specialization in TurboFan")
 DEFINE_BOOL(turbo_deoptimization, false, "enable deoptimization in TurboFan")
 DEFINE_BOOL(turbo_inlining, false, "enable inlining in TurboFan")
-DEFINE_BOOL(turbo_inlining_intrinsics, false,
-            "enable inlining of intrinsics in TurboFan")
 DEFINE_BOOL(trace_turbo_inlining, false, "trace TurboFan inlining")
 DEFINE_BOOL(loop_assignment_analysis, true, "perform loop assignment analysis")
-DEFINE_IMPLICATION(turbo_inlining_intrinsics, turbo_inlining)
 DEFINE_IMPLICATION(turbo_inlining, turbo_types)
 DEFINE_BOOL(turbo_profiling, false, "enable profiling in TurboFan")
 // TODO(dcarney): this is just for experimentation, remove when default.
index 76cbb8f..bd4038e 100644 (file)
@@ -11,7 +11,6 @@ using namespace v8::internal::compiler;
 uint32_t flags = CompilationInfo::kInliningEnabled;
 
 TEST(IsSmi) {
-  FLAG_turbo_inlining_intrinsics = true;
   FLAG_turbo_deoptimization = true;
   FunctionTester T("(function(a) { return %_IsSmi(a); })", flags);
 
@@ -25,7 +24,6 @@ TEST(IsSmi) {
 
 
 TEST(IsNonNegativeSmi) {
-  FLAG_turbo_inlining_intrinsics = true;
   FLAG_turbo_deoptimization = true;
   FunctionTester T("(function(a) { return %_IsNonNegativeSmi(a); })", flags);
 
@@ -39,7 +37,6 @@ TEST(IsNonNegativeSmi) {
 
 
 TEST(IsMinusZero) {
-  FLAG_turbo_inlining_intrinsics = true;
   FLAG_turbo_deoptimization = true;
   FunctionTester T("(function(a) { return %_IsMinusZero(a); })", flags);
 
@@ -53,7 +50,6 @@ TEST(IsMinusZero) {
 
 
 TEST(IsArray) {
-  FLAG_turbo_inlining_intrinsics = true;
   FLAG_turbo_deoptimization = true;
   FunctionTester T("(function(a) { return %_IsArray(a); })", flags);
 
@@ -69,7 +65,6 @@ TEST(IsArray) {
 
 
 TEST(IsObject) {
-  FLAG_turbo_inlining_intrinsics = true;
   FLAG_turbo_deoptimization = true;
   FunctionTester T("(function(a) { return %_IsObject(a); })", flags);
 
@@ -85,7 +80,6 @@ TEST(IsObject) {
 
 
 TEST(IsFunction) {
-  FLAG_turbo_inlining_intrinsics = true;
   FLAG_turbo_deoptimization = true;
   FunctionTester T("(function(a) { return %_IsFunction(a); })", flags);
 
@@ -101,7 +95,6 @@ TEST(IsFunction) {
 
 
 TEST(IsRegExp) {
-  FLAG_turbo_inlining_intrinsics = true;
   FLAG_turbo_deoptimization = true;
   FunctionTester T("(function(a) { return %_IsRegExp(a); })", flags);
 
@@ -117,7 +110,6 @@ TEST(IsRegExp) {
 
 
 TEST(ClassOf) {
-  FLAG_turbo_inlining_intrinsics = true;
   FLAG_turbo_deoptimization = true;
   FunctionTester T("(function(a) { return %_ClassOf(a); })", flags);
 
@@ -133,7 +125,6 @@ TEST(ClassOf) {
 
 
 TEST(ObjectEquals) {
-  FLAG_turbo_inlining_intrinsics = true;
   FLAG_turbo_deoptimization = true;
   FunctionTester T("(function(a,b) { return %_ObjectEquals(a,b); })", flags);
   CompileRun("var o = {}");
@@ -148,7 +139,6 @@ TEST(ObjectEquals) {
 
 
 TEST(ValueOf) {
-  FLAG_turbo_inlining_intrinsics = true;
   FLAG_turbo_deoptimization = true;
   FunctionTester T("(function(a) { return %_ValueOf(a); })", flags);
 
@@ -160,7 +150,6 @@ TEST(ValueOf) {
 
 
 TEST(SetValueOf) {
-  FLAG_turbo_inlining_intrinsics = true;
   FLAG_turbo_deoptimization = true;
   FunctionTester T("(function(a,b) { return %_SetValueOf(a,b); })", flags);
 
@@ -171,7 +160,6 @@ TEST(SetValueOf) {
 
 
 TEST(StringCharFromCode) {
-  FLAG_turbo_inlining_intrinsics = true;
   FLAG_turbo_deoptimization = true;
   FunctionTester T("(function(a) { return %_StringCharFromCode(a); })", flags);
 
@@ -182,7 +170,6 @@ TEST(StringCharFromCode) {
 
 
 TEST(StringCharAt) {
-  FLAG_turbo_inlining_intrinsics = true;
   FLAG_turbo_deoptimization = true;
   FunctionTester T("(function(a,b) { return %_StringCharAt(a,b); })", flags);
 
@@ -193,7 +180,6 @@ TEST(StringCharAt) {
 
 
 TEST(StringCharCodeAt) {
-  FLAG_turbo_inlining_intrinsics = true;
   FLAG_turbo_deoptimization = true;
   FunctionTester T("(function(a,b) { return %_StringCharCodeAt(a,b); })",
                    flags);
@@ -205,7 +191,6 @@ TEST(StringCharCodeAt) {
 
 
 TEST(StringAdd) {
-  FLAG_turbo_inlining_intrinsics = true;
   FLAG_turbo_deoptimization = true;
   FunctionTester T("(function(a,b) { return %_StringAdd(a,b); })", flags);
 
@@ -216,7 +201,6 @@ TEST(StringAdd) {
 
 
 TEST(StringSubString) {
-  FLAG_turbo_inlining_intrinsics = true;
   FLAG_turbo_deoptimization = true;
   FunctionTester T("(function(a,b) { return %_SubString(a,b,b+3); })", flags);
 
@@ -227,7 +211,6 @@ TEST(StringSubString) {
 
 
 TEST(StringCompare) {
-  FLAG_turbo_inlining_intrinsics = true;
   FLAG_turbo_deoptimization = true;
   FunctionTester T("(function(a,b) { return %_StringCompare(a,b); })", flags);
 
@@ -238,7 +221,6 @@ TEST(StringCompare) {
 
 
 TEST(CallFunction) {
-  FLAG_turbo_inlining_intrinsics = true;
   FLAG_turbo_deoptimization = true;
   FunctionTester T("(function(a,b) { return %_CallFunction(a, 1, 2, 3, b); })",
                    flags);
diff --git a/test/unittests/compiler/js-intrinsic-lowering-unittest.cc b/test/unittests/compiler/js-intrinsic-lowering-unittest.cc
new file mode 100644 (file)
index 0000000..20d5c06
--- /dev/null
@@ -0,0 +1,215 @@
+// Copyright 2015 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/compiler/access-builder.h"
+#include "src/compiler/js-graph.h"
+#include "src/compiler/js-intrinsic-lowering.h"
+#include "src/compiler/js-operator.h"
+#include "test/unittests/compiler/graph-unittest.h"
+#include "test/unittests/compiler/node-test-utils.h"
+#include "testing/gmock-support.h"
+
+using testing::_;
+using testing::AllOf;
+using testing::BitEq;
+using testing::Capture;
+using testing::CaptureEq;
+
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+class JSIntrinsicLoweringTest : public GraphTest {
+ public:
+  JSIntrinsicLoweringTest() : GraphTest(3), javascript_(zone()) {}
+  ~JSIntrinsicLoweringTest() OVERRIDE {}
+
+ protected:
+  Reduction Reduce(Node* node) {
+    MachineOperatorBuilder machine(zone());
+    JSGraph jsgraph(isolate(), graph(), common(), javascript(), &machine);
+    JSIntrinsicLowering reducer(&jsgraph);
+    return reducer.Reduce(node);
+  }
+
+  JSOperatorBuilder* javascript() { return &javascript_; }
+
+ private:
+  JSOperatorBuilder javascript_;
+};
+
+
+// -----------------------------------------------------------------------------
+// %_IsSmi
+
+
+TEST_F(JSIntrinsicLoweringTest, InlineIsSmi) {
+  Node* const input = Parameter(0);
+  Node* const context = Parameter(1);
+  Node* const effect = graph()->start();
+  Node* const control = graph()->start();
+  Reduction const r = Reduce(
+      graph()->NewNode(javascript()->CallRuntime(Runtime::kInlineIsSmi, 1),
+                       input, context, effect, control));
+  ASSERT_TRUE(r.Changed());
+  EXPECT_THAT(r.replacement(), IsObjectIsSmi(input));
+}
+
+
+// -----------------------------------------------------------------------------
+// %_IsNonNegativeSmi
+
+
+TEST_F(JSIntrinsicLoweringTest, InlineIsNonNegativeSmi) {
+  Node* const input = Parameter(0);
+  Node* const context = Parameter(1);
+  Node* const effect = graph()->start();
+  Node* const control = graph()->start();
+  Reduction const r = Reduce(graph()->NewNode(
+      javascript()->CallRuntime(Runtime::kInlineIsNonNegativeSmi, 1), input,
+      context, effect, control));
+  ASSERT_TRUE(r.Changed());
+  EXPECT_THAT(r.replacement(), IsObjectIsNonNegativeSmi(input));
+}
+
+
+// -----------------------------------------------------------------------------
+// %_IsArray
+
+
+TEST_F(JSIntrinsicLoweringTest, InlineIsArray) {
+  Node* const input = Parameter(0);
+  Node* const context = Parameter(1);
+  Node* const effect = graph()->start();
+  Node* const control = graph()->start();
+  Reduction const r = Reduce(
+      graph()->NewNode(javascript()->CallRuntime(Runtime::kInlineIsArray, 1),
+                       input, context, effect, control));
+  ASSERT_TRUE(r.Changed());
+
+  Node* phi = r.replacement();
+  Capture<Node*> branch, if_false;
+  EXPECT_THAT(
+      phi,
+      IsPhi(
+          static_cast<MachineType>(kTypeBool | kRepTagged), IsFalseConstant(),
+          IsWord32Equal(IsLoadField(AccessBuilder::ForMapInstanceType(),
+                                    IsLoadField(AccessBuilder::ForMap(), input,
+                                                effect, CaptureEq(&if_false)),
+                                    effect, _),
+                        IsInt32Constant(JS_ARRAY_TYPE)),
+          IsMerge(IsIfTrue(AllOf(CaptureEq(&branch),
+                                 IsBranch(IsObjectIsSmi(input), control))),
+                  AllOf(CaptureEq(&if_false), IsIfFalse(CaptureEq(&branch))))));
+}
+
+
+// -----------------------------------------------------------------------------
+// %_IsFunction
+
+
+TEST_F(JSIntrinsicLoweringTest, InlineIsFunction) {
+  Node* const input = Parameter(0);
+  Node* const context = Parameter(1);
+  Node* const effect = graph()->start();
+  Node* const control = graph()->start();
+  Reduction const r = Reduce(
+      graph()->NewNode(javascript()->CallRuntime(Runtime::kInlineIsFunction, 1),
+                       input, context, effect, control));
+  ASSERT_TRUE(r.Changed());
+
+  Node* phi = r.replacement();
+  Capture<Node*> branch, if_false;
+  EXPECT_THAT(
+      phi,
+      IsPhi(
+          static_cast<MachineType>(kTypeBool | kRepTagged), IsFalseConstant(),
+          IsWord32Equal(IsLoadField(AccessBuilder::ForMapInstanceType(),
+                                    IsLoadField(AccessBuilder::ForMap(), input,
+                                                effect, CaptureEq(&if_false)),
+                                    effect, _),
+                        IsInt32Constant(JS_FUNCTION_TYPE)),
+          IsMerge(IsIfTrue(AllOf(CaptureEq(&branch),
+                                 IsBranch(IsObjectIsSmi(input), control))),
+                  AllOf(CaptureEq(&if_false), IsIfFalse(CaptureEq(&branch))))));
+}
+
+
+// -----------------------------------------------------------------------------
+// %_IsRegExp
+
+
+TEST_F(JSIntrinsicLoweringTest, InlineIsRegExp) {
+  Node* const input = Parameter(0);
+  Node* const context = Parameter(1);
+  Node* const effect = graph()->start();
+  Node* const control = graph()->start();
+  Reduction const r = Reduce(
+      graph()->NewNode(javascript()->CallRuntime(Runtime::kInlineIsRegExp, 1),
+                       input, context, effect, control));
+  ASSERT_TRUE(r.Changed());
+
+  Node* phi = r.replacement();
+  Capture<Node*> branch, if_false;
+  EXPECT_THAT(
+      phi,
+      IsPhi(
+          static_cast<MachineType>(kTypeBool | kRepTagged), IsFalseConstant(),
+          IsWord32Equal(IsLoadField(AccessBuilder::ForMapInstanceType(),
+                                    IsLoadField(AccessBuilder::ForMap(), input,
+                                                effect, CaptureEq(&if_false)),
+                                    effect, _),
+                        IsInt32Constant(JS_REGEXP_TYPE)),
+          IsMerge(IsIfTrue(AllOf(CaptureEq(&branch),
+                                 IsBranch(IsObjectIsSmi(input), control))),
+                  AllOf(CaptureEq(&if_false), IsIfFalse(CaptureEq(&branch))))));
+}
+
+
+// -----------------------------------------------------------------------------
+// %_ValueOf
+
+
+TEST_F(JSIntrinsicLoweringTest, InlineValueOf) {
+  Node* const input = Parameter(0);
+  Node* const context = Parameter(1);
+  Node* const effect = graph()->start();
+  Node* const control = graph()->start();
+  Reduction const r = Reduce(
+      graph()->NewNode(javascript()->CallRuntime(Runtime::kInlineValueOf, 1),
+                       input, context, effect, control));
+  ASSERT_TRUE(r.Changed());
+
+  Node* phi = r.replacement();
+  Capture<Node*> branch0, if_false0, branch1, if_true1;
+  EXPECT_THAT(
+      phi,
+      IsPhi(
+          kMachAnyTagged, input,
+          IsPhi(kMachAnyTagged, IsLoadField(AccessBuilder::ForValue(), input,
+                                            effect, CaptureEq(&if_true1)),
+                input,
+                IsMerge(
+                    AllOf(CaptureEq(&if_true1), IsIfTrue(CaptureEq(&branch1))),
+                    IsIfFalse(AllOf(
+                        CaptureEq(&branch1),
+                        IsBranch(
+                            IsWord32Equal(
+                                IsLoadField(
+                                    AccessBuilder::ForMapInstanceType(),
+                                    IsLoadField(AccessBuilder::ForMap(), input,
+                                                effect, CaptureEq(&if_false0)),
+                                    effect, _),
+                                IsInt32Constant(JS_VALUE_TYPE)),
+                            CaptureEq(&if_false0)))))),
+          IsMerge(
+              IsIfTrue(AllOf(CaptureEq(&branch0),
+                             IsBranch(IsObjectIsSmi(input), control))),
+              AllOf(CaptureEq(&if_false0), IsIfFalse(CaptureEq(&branch0))))));
+}
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
index 5f38b72..18b0729 100644 (file)
@@ -1473,6 +1473,8 @@ IS_UNOP_MATCHER(Float64RoundTruncate)
 IS_UNOP_MATCHER(Float64RoundTiesAway)
 IS_UNOP_MATCHER(NumberToInt32)
 IS_UNOP_MATCHER(NumberToUint32)
+IS_UNOP_MATCHER(ObjectIsSmi)
+IS_UNOP_MATCHER(ObjectIsNonNegativeSmi)
 #undef IS_UNOP_MATCHER
 
 }  // namespace compiler
index 736cf0f..d49d2cf 100644 (file)
@@ -131,6 +131,8 @@ Matcher<Node*> IsStoreElement(const Matcher<ElementAccess>& access_matcher,
                               const Matcher<Node*>& value_matcher,
                               const Matcher<Node*>& effect_matcher,
                               const Matcher<Node*>& control_matcher);
+Matcher<Node*> IsObjectIsSmi(const Matcher<Node*>& value_matcher);
+Matcher<Node*> IsObjectIsNonNegativeSmi(const Matcher<Node*>& value_matcher);
 
 Matcher<Node*> IsLoad(const Matcher<LoadRepresentation>& rep_matcher,
                       const Matcher<Node*>& base_matcher,
index 1327694..285ce89 100644 (file)
@@ -51,6 +51,7 @@
         'compiler/instruction-sequence-unittest.cc',
         'compiler/instruction-sequence-unittest.h',
         'compiler/js-builtin-reducer-unittest.cc',
+        'compiler/js-intrinsic-lowering-unittest.cc',
         'compiler/js-operator-unittest.cc',
         'compiler/js-typed-lowering-unittest.cc',
         'compiler/load-elimination-unittest.cc',
index 9443911..e8081a7 100644 (file)
         '../../src/compiler/js-graph.h',
         '../../src/compiler/js-inlining.cc',
         '../../src/compiler/js-inlining.h',
-        '../../src/compiler/js-intrinsic-builder.cc',
-        '../../src/compiler/js-intrinsic-builder.h',
+        '../../src/compiler/js-intrinsic-lowering.cc',
+        '../../src/compiler/js-intrinsic-lowering.h',
         '../../src/compiler/js-operator.cc',
         '../../src/compiler/js-operator.h',
         '../../src/compiler/js-typed-lowering.cc',