OLD | NEW |
(Empty) | |
| 1 // Copyright 2016 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "src/compiler/typed-optimization.h" |
| 6 |
| 7 #include "src/compilation-dependencies.h" |
| 8 #include "src/compiler/js-graph.h" |
| 9 #include "src/compiler/node-properties.h" |
| 10 #include "src/compiler/simplified-operator.h" |
| 11 #include "src/isolate-inl.h" |
| 12 #include "src/type-cache.h" |
| 13 |
| 14 namespace v8 { |
| 15 namespace internal { |
| 16 namespace compiler { |
| 17 |
| 18 TypedOptimization::TypedOptimization(Editor* editor, |
| 19 CompilationDependencies* dependencies, |
| 20 Flags flags, JSGraph* jsgraph) |
| 21 : AdvancedReducer(editor), |
| 22 dependencies_(dependencies), |
| 23 flags_(flags), |
| 24 jsgraph_(jsgraph), |
| 25 true_type_(Type::Constant(factory()->true_value(), graph()->zone())), |
| 26 false_type_(Type::Constant(factory()->false_value(), graph()->zone())), |
| 27 type_cache_(TypeCache::Get()) {} |
| 28 |
| 29 TypedOptimization::~TypedOptimization() {} |
| 30 |
| 31 Reduction TypedOptimization::Reduce(Node* node) { |
| 32 // Check if the output type is a singleton. In that case we already know the |
| 33 // result value and can simply replace the node if it's eliminable. |
| 34 if (!NodeProperties::IsConstant(node) && NodeProperties::IsTyped(node) && |
| 35 node->op()->HasProperty(Operator::kEliminatable)) { |
| 36 // We can only constant-fold nodes here, that are known to not cause any |
| 37 // side-effect, may it be a JavaScript observable side-effect or a possible |
| 38 // eager deoptimization exit (i.e. {node} has an operator that doesn't have |
| 39 // the Operator::kNoDeopt property). |
| 40 Type* upper = NodeProperties::GetType(node); |
| 41 if (upper->IsInhabited()) { |
| 42 if (upper->IsConstant()) { |
| 43 Node* replacement = jsgraph()->Constant(upper->AsConstant()->Value()); |
| 44 ReplaceWithValue(node, replacement); |
| 45 return Changed(replacement); |
| 46 } else if (upper->Is(Type::MinusZero())) { |
| 47 Node* replacement = jsgraph()->Constant(factory()->minus_zero_value()); |
| 48 ReplaceWithValue(node, replacement); |
| 49 return Changed(replacement); |
| 50 } else if (upper->Is(Type::NaN())) { |
| 51 Node* replacement = jsgraph()->NaNConstant(); |
| 52 ReplaceWithValue(node, replacement); |
| 53 return Changed(replacement); |
| 54 } else if (upper->Is(Type::Null())) { |
| 55 Node* replacement = jsgraph()->NullConstant(); |
| 56 ReplaceWithValue(node, replacement); |
| 57 return Changed(replacement); |
| 58 } else if (upper->Is(Type::PlainNumber()) && |
| 59 upper->Min() == upper->Max()) { |
| 60 Node* replacement = jsgraph()->Constant(upper->Min()); |
| 61 ReplaceWithValue(node, replacement); |
| 62 return Changed(replacement); |
| 63 } else if (upper->Is(Type::Undefined())) { |
| 64 Node* replacement = jsgraph()->UndefinedConstant(); |
| 65 ReplaceWithValue(node, replacement); |
| 66 return Changed(replacement); |
| 67 } |
| 68 } |
| 69 } |
| 70 switch (node->opcode()) { |
| 71 case IrOpcode::kCheckMaps: |
| 72 return ReduceCheckMaps(node); |
| 73 case IrOpcode::kCheckString: |
| 74 return ReduceCheckString(node); |
| 75 case IrOpcode::kLoadField: |
| 76 return ReduceLoadField(node); |
| 77 case IrOpcode::kNumberCeil: |
| 78 case IrOpcode::kNumberFloor: |
| 79 case IrOpcode::kNumberRound: |
| 80 case IrOpcode::kNumberTrunc: |
| 81 return ReduceNumberRoundop(node); |
| 82 case IrOpcode::kPhi: |
| 83 return ReducePhi(node); |
| 84 case IrOpcode::kSelect: |
| 85 return ReduceSelect(node); |
| 86 default: |
| 87 break; |
| 88 } |
| 89 return NoChange(); |
| 90 } |
| 91 |
| 92 namespace { |
| 93 |
| 94 MaybeHandle<Map> GetStableMapFromObjectType(Type* object_type) { |
| 95 if (object_type->IsConstant() && |
| 96 object_type->AsConstant()->Value()->IsHeapObject()) { |
| 97 Handle<Map> object_map( |
| 98 Handle<HeapObject>::cast(object_type->AsConstant()->Value())->map()); |
| 99 if (object_map->is_stable()) return object_map; |
| 100 } else if (object_type->IsClass()) { |
| 101 Handle<Map> object_map = object_type->AsClass()->Map(); |
| 102 if (object_map->is_stable()) return object_map; |
| 103 } |
| 104 return MaybeHandle<Map>(); |
| 105 } |
| 106 |
| 107 } // namespace |
| 108 |
| 109 Reduction TypedOptimization::ReduceCheckMaps(Node* node) { |
| 110 // The CheckMaps(o, ...map...) can be eliminated if map is stable and |
| 111 // either |
| 112 // (a) o has type Constant(object) and map == object->map, or |
| 113 // (b) o has type Class(map), |
| 114 // and either |
| 115 // (1) map cannot transition further, or |
| 116 // (2) we can add a code dependency on the stability of map |
| 117 // (to guard the Constant type information). |
| 118 Node* const object = NodeProperties::GetValueInput(node, 0); |
| 119 Type* const object_type = NodeProperties::GetType(object); |
| 120 Node* const effect = NodeProperties::GetEffectInput(node); |
| 121 Handle<Map> object_map; |
| 122 if (GetStableMapFromObjectType(object_type).ToHandle(&object_map)) { |
| 123 for (int i = 1; i < node->op()->ValueInputCount(); ++i) { |
| 124 Node* const map = NodeProperties::GetValueInput(node, i); |
| 125 Type* const map_type = NodeProperties::GetType(map); |
| 126 if (map_type->IsConstant() && |
| 127 map_type->AsConstant()->Value().is_identical_to(object_map)) { |
| 128 if (object_map->CanTransition()) { |
| 129 dependencies()->AssumeMapStable(object_map); |
| 130 } |
| 131 return Replace(effect); |
| 132 } |
| 133 } |
| 134 } |
| 135 return NoChange(); |
| 136 } |
| 137 |
| 138 Reduction TypedOptimization::ReduceCheckString(Node* node) { |
| 139 Node* const input = NodeProperties::GetValueInput(node, 0); |
| 140 Type* const input_type = NodeProperties::GetType(input); |
| 141 if (input_type->Is(Type::String())) { |
| 142 ReplaceWithValue(node, input); |
| 143 return Replace(input); |
| 144 } |
| 145 return NoChange(); |
| 146 } |
| 147 |
| 148 Reduction TypedOptimization::ReduceLoadField(Node* node) { |
| 149 Node* const object = NodeProperties::GetValueInput(node, 0); |
| 150 Type* const object_type = NodeProperties::GetType(object); |
| 151 FieldAccess const& access = FieldAccessOf(node->op()); |
| 152 if (access.base_is_tagged == kTaggedBase && |
| 153 access.offset == HeapObject::kMapOffset) { |
| 154 // We can replace LoadField[Map](o) with map if is stable and either |
| 155 // (a) o has type Constant(object) and map == object->map, or |
| 156 // (b) o has type Class(map), |
| 157 // and either |
| 158 // (1) map cannot transition further, or |
| 159 // (2) deoptimization is enabled and we can add a code dependency on the |
| 160 // stability of map (to guard the Constant type information). |
| 161 Handle<Map> object_map; |
| 162 if (GetStableMapFromObjectType(object_type).ToHandle(&object_map)) { |
| 163 if (object_map->CanTransition()) { |
| 164 if (flags() & kDeoptimizationEnabled) { |
| 165 dependencies()->AssumeMapStable(object_map); |
| 166 } else { |
| 167 return NoChange(); |
| 168 } |
| 169 } |
| 170 Node* const value = jsgraph()->HeapConstant(object_map); |
| 171 ReplaceWithValue(node, value); |
| 172 return Replace(value); |
| 173 } |
| 174 } |
| 175 return NoChange(); |
| 176 } |
| 177 |
| 178 Reduction TypedOptimization::ReduceNumberRoundop(Node* node) { |
| 179 Node* const input = NodeProperties::GetValueInput(node, 0); |
| 180 Type* const input_type = NodeProperties::GetType(input); |
| 181 if (input_type->Is(type_cache_.kIntegerOrMinusZeroOrNaN)) { |
| 182 return Replace(input); |
| 183 } |
| 184 return NoChange(); |
| 185 } |
| 186 |
| 187 Reduction TypedOptimization::ReducePhi(Node* node) { |
| 188 // Try to narrow the type of the Phi {node}, which might be more precise now |
| 189 // after lowering based on types, i.e. a SpeculativeNumberAdd has a more |
| 190 // precise type than the JSAdd that was in the graph when the Typer was run. |
| 191 DCHECK_EQ(IrOpcode::kPhi, node->opcode()); |
| 192 int arity = node->op()->ValueInputCount(); |
| 193 Type* type = NodeProperties::GetType(node->InputAt(0)); |
| 194 for (int i = 1; i < arity; ++i) { |
| 195 type = Type::Union(type, NodeProperties::GetType(node->InputAt(i)), |
| 196 graph()->zone()); |
| 197 } |
| 198 Type* const node_type = NodeProperties::GetType(node); |
| 199 if (!node_type->Is(type)) { |
| 200 type = Type::Intersect(node_type, type, graph()->zone()); |
| 201 NodeProperties::SetType(node, type); |
| 202 return Changed(node); |
| 203 } |
| 204 return NoChange(); |
| 205 } |
| 206 |
| 207 Reduction TypedOptimization::ReduceSelect(Node* node) { |
| 208 DCHECK_EQ(IrOpcode::kSelect, node->opcode()); |
| 209 Node* const condition = NodeProperties::GetValueInput(node, 0); |
| 210 Type* const condition_type = NodeProperties::GetType(condition); |
| 211 Node* const vtrue = NodeProperties::GetValueInput(node, 1); |
| 212 Type* const vtrue_type = NodeProperties::GetType(vtrue); |
| 213 Node* const vfalse = NodeProperties::GetValueInput(node, 2); |
| 214 Type* const vfalse_type = NodeProperties::GetType(vfalse); |
| 215 if (condition_type->Is(true_type_)) { |
| 216 // Select(condition:true, vtrue, vfalse) => vtrue |
| 217 return Replace(vtrue); |
| 218 } |
| 219 if (condition_type->Is(false_type_)) { |
| 220 // Select(condition:false, vtrue, vfalse) => vfalse |
| 221 return Replace(vfalse); |
| 222 } |
| 223 if (vtrue_type->Is(true_type_) && vfalse_type->Is(false_type_)) { |
| 224 // Select(condition, vtrue:true, vfalse:false) => condition |
| 225 return Replace(condition); |
| 226 } |
| 227 if (vtrue_type->Is(false_type_) && vfalse_type->Is(true_type_)) { |
| 228 // Select(condition, vtrue:false, vfalse:true) => BooleanNot(condition) |
| 229 node->TrimInputCount(1); |
| 230 NodeProperties::ChangeOp(node, simplified()->BooleanNot()); |
| 231 return Changed(node); |
| 232 } |
| 233 // Try to narrow the type of the Select {node}, which might be more precise |
| 234 // now after lowering based on types. |
| 235 Type* type = Type::Union(vtrue_type, vfalse_type, graph()->zone()); |
| 236 Type* const node_type = NodeProperties::GetType(node); |
| 237 if (!node_type->Is(type)) { |
| 238 type = Type::Intersect(node_type, type, graph()->zone()); |
| 239 NodeProperties::SetType(node, type); |
| 240 return Changed(node); |
| 241 } |
| 242 return NoChange(); |
| 243 } |
| 244 |
| 245 Factory* TypedOptimization::factory() const { return isolate()->factory(); } |
| 246 |
| 247 Graph* TypedOptimization::graph() const { return jsgraph()->graph(); } |
| 248 |
| 249 Isolate* TypedOptimization::isolate() const { return jsgraph()->isolate(); } |
| 250 |
| 251 SimplifiedOperatorBuilder* TypedOptimization::simplified() const { |
| 252 return jsgraph()->simplified(); |
| 253 } |
| 254 |
| 255 } // namespace compiler |
| 256 } // namespace internal |
| 257 } // namespace v8 |
OLD | NEW |