"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",
#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"
case IrOpcode::kJSCallFunction:
inliner_->TryInlineJSCall(node);
break;
- case IrOpcode::kJSCallRuntime:
- if (FLAG_turbo_inlining_intrinsics) {
- inliner_->TryInlineRuntimeCall(node);
- }
- break;
default:
break;
}
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
void Inline();
void TryInlineJSCall(Node* node);
- void TryInlineRuntimeCall(Node* node);
private:
friend class InlinerVisitor;
+++ /dev/null
-// 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
+++ /dev/null
-// 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_
--- /dev/null
+// 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
--- /dev/null
+// 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_
#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"
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);
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;
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);
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());
}
"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.
uint32_t flags = CompilationInfo::kInliningEnabled;
TEST(IsSmi) {
- FLAG_turbo_inlining_intrinsics = true;
FLAG_turbo_deoptimization = true;
FunctionTester T("(function(a) { return %_IsSmi(a); })", flags);
TEST(IsNonNegativeSmi) {
- FLAG_turbo_inlining_intrinsics = true;
FLAG_turbo_deoptimization = true;
FunctionTester T("(function(a) { return %_IsNonNegativeSmi(a); })", flags);
TEST(IsMinusZero) {
- FLAG_turbo_inlining_intrinsics = true;
FLAG_turbo_deoptimization = true;
FunctionTester T("(function(a) { return %_IsMinusZero(a); })", flags);
TEST(IsArray) {
- FLAG_turbo_inlining_intrinsics = true;
FLAG_turbo_deoptimization = true;
FunctionTester T("(function(a) { return %_IsArray(a); })", flags);
TEST(IsObject) {
- FLAG_turbo_inlining_intrinsics = true;
FLAG_turbo_deoptimization = true;
FunctionTester T("(function(a) { return %_IsObject(a); })", flags);
TEST(IsFunction) {
- FLAG_turbo_inlining_intrinsics = true;
FLAG_turbo_deoptimization = true;
FunctionTester T("(function(a) { return %_IsFunction(a); })", flags);
TEST(IsRegExp) {
- FLAG_turbo_inlining_intrinsics = true;
FLAG_turbo_deoptimization = true;
FunctionTester T("(function(a) { return %_IsRegExp(a); })", flags);
TEST(ClassOf) {
- FLAG_turbo_inlining_intrinsics = true;
FLAG_turbo_deoptimization = true;
FunctionTester T("(function(a) { return %_ClassOf(a); })", flags);
TEST(ObjectEquals) {
- FLAG_turbo_inlining_intrinsics = true;
FLAG_turbo_deoptimization = true;
FunctionTester T("(function(a,b) { return %_ObjectEquals(a,b); })", flags);
CompileRun("var o = {}");
TEST(ValueOf) {
- FLAG_turbo_inlining_intrinsics = true;
FLAG_turbo_deoptimization = true;
FunctionTester T("(function(a) { return %_ValueOf(a); })", flags);
TEST(SetValueOf) {
- FLAG_turbo_inlining_intrinsics = true;
FLAG_turbo_deoptimization = true;
FunctionTester T("(function(a,b) { return %_SetValueOf(a,b); })", flags);
TEST(StringCharFromCode) {
- FLAG_turbo_inlining_intrinsics = true;
FLAG_turbo_deoptimization = true;
FunctionTester T("(function(a) { return %_StringCharFromCode(a); })", flags);
TEST(StringCharAt) {
- FLAG_turbo_inlining_intrinsics = true;
FLAG_turbo_deoptimization = true;
FunctionTester T("(function(a,b) { return %_StringCharAt(a,b); })", flags);
TEST(StringCharCodeAt) {
- FLAG_turbo_inlining_intrinsics = true;
FLAG_turbo_deoptimization = true;
FunctionTester T("(function(a,b) { return %_StringCharCodeAt(a,b); })",
flags);
TEST(StringAdd) {
- FLAG_turbo_inlining_intrinsics = true;
FLAG_turbo_deoptimization = true;
FunctionTester T("(function(a,b) { return %_StringAdd(a,b); })", flags);
TEST(StringSubString) {
- FLAG_turbo_inlining_intrinsics = true;
FLAG_turbo_deoptimization = true;
FunctionTester T("(function(a,b) { return %_SubString(a,b,b+3); })", flags);
TEST(StringCompare) {
- FLAG_turbo_inlining_intrinsics = true;
FLAG_turbo_deoptimization = true;
FunctionTester T("(function(a,b) { return %_StringCompare(a,b); })", flags);
TEST(CallFunction) {
- FLAG_turbo_inlining_intrinsics = true;
FLAG_turbo_deoptimization = true;
FunctionTester T("(function(a,b) { return %_CallFunction(a, 1, 2, 3, b); })",
flags);
--- /dev/null
+// 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
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
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,
'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',
'../../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',