Commit 4f1597a9 authored by bmeurer's avatar bmeurer Committed by Commit bot

[turbofan] Add new JSIntrinsicsLowering reducer.

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}
parent 8eb58b85
......@@ -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",
......
......@@ -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
......@@ -21,7 +21,6 @@ class JSInliner {
void Inline();
void TryInlineJSCall(Node* node);
void TryInlineRuntimeCall(Node* node);
private:
friend class InlinerVisitor;
......
// 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
// 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_
// 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
// 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_
......@@ -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);
......
......@@ -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);
......
......@@ -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());
}
......
......@@ -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.
......
......@@ -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);
......
// 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
......@@ -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
......
......@@ -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,
......
......@@ -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',
......
......@@ -466,8 +466,8 @@
'../../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',
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment