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 |