aboutsummaryrefslogtreecommitdiff
path: root/deps/v8/src/compiler/typed-optimization.cc
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/src/compiler/typed-optimization.cc')
-rw-r--r--deps/v8/src/compiler/typed-optimization.cc253
1 files changed, 253 insertions, 0 deletions
diff --git a/deps/v8/src/compiler/typed-optimization.cc b/deps/v8/src/compiler/typed-optimization.cc
new file mode 100644
index 0000000000..c5e8648ca5
--- /dev/null
+++ b/deps/v8/src/compiler/typed-optimization.cc
@@ -0,0 +1,253 @@
+// 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/compiler/type-cache.h"
+#include "src/isolate-inl.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)) {
+ // TODO(v8:5303): We must not eliminate FinishRegion here. This special
+ // case can be removed once we have separate operators for value and
+ // effect regions.
+ if (node->opcode() == IrOpcode::kFinishRegion) return NoChange();
+ // 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;
+ }
+ return MaybeHandle<Map>();
+}
+
+} // namespace
+
+Reduction TypedOptimization::ReduceCheckMaps(Node* node) {
+ // The CheckMaps(o, ...map...) can be eliminated if map is stable,
+ // o has type Constant(object) and map == object->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
+ // o has type Constant(object) and map == object->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