diff options
Diffstat (limited to 'deps/v8/src/compiler/typed-optimization.cc')
-rw-r--r-- | deps/v8/src/compiler/typed-optimization.cc | 253 |
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 |