| Index: src/compiler/typed-optimization.cc
|
| diff --git a/src/compiler/typed-optimization.cc b/src/compiler/typed-optimization.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..7ad87940738199ddc3e35a73fb846a22e9fc5121
|
| --- /dev/null
|
| +++ b/src/compiler/typed-optimization.cc
|
| @@ -0,0 +1,257 @@
|
| +// Copyright 2016 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/typed-optimization.h"
|
| +
|
| +#include "src/compilation-dependencies.h"
|
| +#include "src/compiler/js-graph.h"
|
| +#include "src/compiler/node-properties.h"
|
| +#include "src/compiler/simplified-operator.h"
|
| +#include "src/isolate-inl.h"
|
| +#include "src/type-cache.h"
|
| +
|
| +namespace v8 {
|
| +namespace internal {
|
| +namespace compiler {
|
| +
|
| +TypedOptimization::TypedOptimization(Editor* editor,
|
| + CompilationDependencies* dependencies,
|
| + Flags flags, JSGraph* jsgraph)
|
| + : AdvancedReducer(editor),
|
| + dependencies_(dependencies),
|
| + flags_(flags),
|
| + jsgraph_(jsgraph),
|
| + true_type_(Type::Constant(factory()->true_value(), graph()->zone())),
|
| + false_type_(Type::Constant(factory()->false_value(), graph()->zone())),
|
| + type_cache_(TypeCache::Get()) {}
|
| +
|
| +TypedOptimization::~TypedOptimization() {}
|
| +
|
| +Reduction TypedOptimization::Reduce(Node* node) {
|
| + // Check if the output type is a singleton. In that case we already know the
|
| + // result value and can simply replace the node if it's eliminable.
|
| + if (!NodeProperties::IsConstant(node) && NodeProperties::IsTyped(node) &&
|
| + node->op()->HasProperty(Operator::kEliminatable)) {
|
| + // We can only constant-fold nodes here, that are known to not cause any
|
| + // side-effect, may it be a JavaScript observable side-effect or a possible
|
| + // eager deoptimization exit (i.e. {node} has an operator that doesn't have
|
| + // the Operator::kNoDeopt property).
|
| + Type* upper = NodeProperties::GetType(node);
|
| + if (upper->IsInhabited()) {
|
| + if (upper->IsConstant()) {
|
| + Node* replacement = jsgraph()->Constant(upper->AsConstant()->Value());
|
| + ReplaceWithValue(node, replacement);
|
| + return Changed(replacement);
|
| + } else if (upper->Is(Type::MinusZero())) {
|
| + Node* replacement = jsgraph()->Constant(factory()->minus_zero_value());
|
| + ReplaceWithValue(node, replacement);
|
| + return Changed(replacement);
|
| + } else if (upper->Is(Type::NaN())) {
|
| + Node* replacement = jsgraph()->NaNConstant();
|
| + ReplaceWithValue(node, replacement);
|
| + return Changed(replacement);
|
| + } else if (upper->Is(Type::Null())) {
|
| + Node* replacement = jsgraph()->NullConstant();
|
| + ReplaceWithValue(node, replacement);
|
| + return Changed(replacement);
|
| + } else if (upper->Is(Type::PlainNumber()) &&
|
| + upper->Min() == upper->Max()) {
|
| + Node* replacement = jsgraph()->Constant(upper->Min());
|
| + ReplaceWithValue(node, replacement);
|
| + return Changed(replacement);
|
| + } else if (upper->Is(Type::Undefined())) {
|
| + Node* replacement = jsgraph()->UndefinedConstant();
|
| + ReplaceWithValue(node, replacement);
|
| + return Changed(replacement);
|
| + }
|
| + }
|
| + }
|
| + switch (node->opcode()) {
|
| + case IrOpcode::kCheckMaps:
|
| + return ReduceCheckMaps(node);
|
| + case IrOpcode::kCheckString:
|
| + return ReduceCheckString(node);
|
| + case IrOpcode::kLoadField:
|
| + return ReduceLoadField(node);
|
| + case IrOpcode::kNumberCeil:
|
| + case IrOpcode::kNumberFloor:
|
| + case IrOpcode::kNumberRound:
|
| + case IrOpcode::kNumberTrunc:
|
| + return ReduceNumberRoundop(node);
|
| + case IrOpcode::kPhi:
|
| + return ReducePhi(node);
|
| + case IrOpcode::kSelect:
|
| + return ReduceSelect(node);
|
| + default:
|
| + break;
|
| + }
|
| + return NoChange();
|
| +}
|
| +
|
| +namespace {
|
| +
|
| +MaybeHandle<Map> GetStableMapFromObjectType(Type* object_type) {
|
| + if (object_type->IsConstant() &&
|
| + object_type->AsConstant()->Value()->IsHeapObject()) {
|
| + Handle<Map> object_map(
|
| + Handle<HeapObject>::cast(object_type->AsConstant()->Value())->map());
|
| + if (object_map->is_stable()) return object_map;
|
| + } else if (object_type->IsClass()) {
|
| + Handle<Map> object_map = object_type->AsClass()->Map();
|
| + if (object_map->is_stable()) return object_map;
|
| + }
|
| + return MaybeHandle<Map>();
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| +Reduction TypedOptimization::ReduceCheckMaps(Node* node) {
|
| + // The CheckMaps(o, ...map...) can be eliminated if map is stable and
|
| + // either
|
| + // (a) o has type Constant(object) and map == object->map, or
|
| + // (b) o has type Class(map),
|
| + // and either
|
| + // (1) map cannot transition further, or
|
| + // (2) we can add a code dependency on the stability of map
|
| + // (to guard the Constant type information).
|
| + Node* const object = NodeProperties::GetValueInput(node, 0);
|
| + Type* const object_type = NodeProperties::GetType(object);
|
| + Node* const effect = NodeProperties::GetEffectInput(node);
|
| + Handle<Map> object_map;
|
| + if (GetStableMapFromObjectType(object_type).ToHandle(&object_map)) {
|
| + for (int i = 1; i < node->op()->ValueInputCount(); ++i) {
|
| + Node* const map = NodeProperties::GetValueInput(node, i);
|
| + Type* const map_type = NodeProperties::GetType(map);
|
| + if (map_type->IsConstant() &&
|
| + map_type->AsConstant()->Value().is_identical_to(object_map)) {
|
| + if (object_map->CanTransition()) {
|
| + dependencies()->AssumeMapStable(object_map);
|
| + }
|
| + return Replace(effect);
|
| + }
|
| + }
|
| + }
|
| + return NoChange();
|
| +}
|
| +
|
| +Reduction TypedOptimization::ReduceCheckString(Node* node) {
|
| + Node* const input = NodeProperties::GetValueInput(node, 0);
|
| + Type* const input_type = NodeProperties::GetType(input);
|
| + if (input_type->Is(Type::String())) {
|
| + ReplaceWithValue(node, input);
|
| + return Replace(input);
|
| + }
|
| + return NoChange();
|
| +}
|
| +
|
| +Reduction TypedOptimization::ReduceLoadField(Node* node) {
|
| + Node* const object = NodeProperties::GetValueInput(node, 0);
|
| + Type* const object_type = NodeProperties::GetType(object);
|
| + FieldAccess const& access = FieldAccessOf(node->op());
|
| + if (access.base_is_tagged == kTaggedBase &&
|
| + access.offset == HeapObject::kMapOffset) {
|
| + // We can replace LoadField[Map](o) with map if is stable and either
|
| + // (a) o has type Constant(object) and map == object->map, or
|
| + // (b) o has type Class(map),
|
| + // and either
|
| + // (1) map cannot transition further, or
|
| + // (2) deoptimization is enabled and we can add a code dependency on the
|
| + // stability of map (to guard the Constant type information).
|
| + Handle<Map> object_map;
|
| + if (GetStableMapFromObjectType(object_type).ToHandle(&object_map)) {
|
| + if (object_map->CanTransition()) {
|
| + if (flags() & kDeoptimizationEnabled) {
|
| + dependencies()->AssumeMapStable(object_map);
|
| + } else {
|
| + return NoChange();
|
| + }
|
| + }
|
| + Node* const value = jsgraph()->HeapConstant(object_map);
|
| + ReplaceWithValue(node, value);
|
| + return Replace(value);
|
| + }
|
| + }
|
| + return NoChange();
|
| +}
|
| +
|
| +Reduction TypedOptimization::ReduceNumberRoundop(Node* node) {
|
| + Node* const input = NodeProperties::GetValueInput(node, 0);
|
| + Type* const input_type = NodeProperties::GetType(input);
|
| + if (input_type->Is(type_cache_.kIntegerOrMinusZeroOrNaN)) {
|
| + return Replace(input);
|
| + }
|
| + return NoChange();
|
| +}
|
| +
|
| +Reduction TypedOptimization::ReducePhi(Node* node) {
|
| + // Try to narrow the type of the Phi {node}, which might be more precise now
|
| + // after lowering based on types, i.e. a SpeculativeNumberAdd has a more
|
| + // precise type than the JSAdd that was in the graph when the Typer was run.
|
| + DCHECK_EQ(IrOpcode::kPhi, node->opcode());
|
| + int arity = node->op()->ValueInputCount();
|
| + Type* type = NodeProperties::GetType(node->InputAt(0));
|
| + for (int i = 1; i < arity; ++i) {
|
| + type = Type::Union(type, NodeProperties::GetType(node->InputAt(i)),
|
| + graph()->zone());
|
| + }
|
| + Type* const node_type = NodeProperties::GetType(node);
|
| + if (!node_type->Is(type)) {
|
| + type = Type::Intersect(node_type, type, graph()->zone());
|
| + NodeProperties::SetType(node, type);
|
| + return Changed(node);
|
| + }
|
| + return NoChange();
|
| +}
|
| +
|
| +Reduction TypedOptimization::ReduceSelect(Node* node) {
|
| + DCHECK_EQ(IrOpcode::kSelect, node->opcode());
|
| + Node* const condition = NodeProperties::GetValueInput(node, 0);
|
| + Type* const condition_type = NodeProperties::GetType(condition);
|
| + Node* const vtrue = NodeProperties::GetValueInput(node, 1);
|
| + Type* const vtrue_type = NodeProperties::GetType(vtrue);
|
| + Node* const vfalse = NodeProperties::GetValueInput(node, 2);
|
| + Type* const vfalse_type = NodeProperties::GetType(vfalse);
|
| + if (condition_type->Is(true_type_)) {
|
| + // Select(condition:true, vtrue, vfalse) => vtrue
|
| + return Replace(vtrue);
|
| + }
|
| + if (condition_type->Is(false_type_)) {
|
| + // Select(condition:false, vtrue, vfalse) => vfalse
|
| + return Replace(vfalse);
|
| + }
|
| + if (vtrue_type->Is(true_type_) && vfalse_type->Is(false_type_)) {
|
| + // Select(condition, vtrue:true, vfalse:false) => condition
|
| + return Replace(condition);
|
| + }
|
| + if (vtrue_type->Is(false_type_) && vfalse_type->Is(true_type_)) {
|
| + // Select(condition, vtrue:false, vfalse:true) => BooleanNot(condition)
|
| + node->TrimInputCount(1);
|
| + NodeProperties::ChangeOp(node, simplified()->BooleanNot());
|
| + return Changed(node);
|
| + }
|
| + // Try to narrow the type of the Select {node}, which might be more precise
|
| + // now after lowering based on types.
|
| + Type* type = Type::Union(vtrue_type, vfalse_type, graph()->zone());
|
| + Type* const node_type = NodeProperties::GetType(node);
|
| + if (!node_type->Is(type)) {
|
| + type = Type::Intersect(node_type, type, graph()->zone());
|
| + NodeProperties::SetType(node, type);
|
| + return Changed(node);
|
| + }
|
| + return NoChange();
|
| +}
|
| +
|
| +Factory* TypedOptimization::factory() const { return isolate()->factory(); }
|
| +
|
| +Graph* TypedOptimization::graph() const { return jsgraph()->graph(); }
|
| +
|
| +Isolate* TypedOptimization::isolate() const { return jsgraph()->isolate(); }
|
| +
|
| +SimplifiedOperatorBuilder* TypedOptimization::simplified() const {
|
| + return jsgraph()->simplified();
|
| +}
|
| +
|
| +} // namespace compiler
|
| +} // namespace internal
|
| +} // namespace v8
|
|
|