Line data Source code
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/compiler/type-cache.h"
12 : #include "src/isolate-inl.h"
13 :
14 : namespace v8 {
15 : namespace internal {
16 : namespace compiler {
17 :
18 395470 : 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 395470 : true_type_(Type::HeapConstant(factory()->true_value(), graph()->zone())),
26 : false_type_(
27 395470 : Type::HeapConstant(factory()->false_value(), graph()->zone())),
28 1186410 : type_cache_(TypeCache::Get()) {}
29 :
30 790940 : TypedOptimization::~TypedOptimization() {}
31 :
32 63414014 : Reduction TypedOptimization::Reduce(Node* node) {
33 : // Check if the output type is a singleton. In that case we already know the
34 : // result value and can simply replace the node if it's eliminable.
35 77419951 : if (!NodeProperties::IsConstant(node) && NodeProperties::IsTyped(node) &&
36 : node->op()->HasProperty(Operator::kEliminatable)) {
37 : // TODO(v8:5303): We must not eliminate FinishRegion here. This special
38 : // case can be removed once we have separate operators for value and
39 : // effect regions.
40 14265994 : if (node->opcode() == IrOpcode::kFinishRegion) return NoChange();
41 : // We can only constant-fold nodes here, that are known to not cause any
42 : // side-effect, may it be a JavaScript observable side-effect or a possible
43 : // eager deoptimization exit (i.e. {node} has an operator that doesn't have
44 : // the Operator::kNoDeopt property).
45 : Type* upper = NodeProperties::GetType(node);
46 14075808 : if (upper->IsInhabited()) {
47 14075624 : if (upper->IsHeapConstant()) {
48 : Node* replacement =
49 49228 : jsgraph()->Constant(upper->AsHeapConstant()->Value());
50 143269 : ReplaceWithValue(node, replacement);
51 : return Changed(replacement);
52 14026391 : } else if (upper->Is(Type::MinusZero())) {
53 26 : Node* replacement = jsgraph()->Constant(factory()->minus_zero_value());
54 : ReplaceWithValue(node, replacement);
55 : return Changed(replacement);
56 14026355 : } else if (upper->Is(Type::NaN())) {
57 702 : Node* replacement = jsgraph()->NaNConstant();
58 : ReplaceWithValue(node, replacement);
59 : return Changed(replacement);
60 14025654 : } else if (upper->Is(Type::Null())) {
61 1 : Node* replacement = jsgraph()->NullConstant();
62 : ReplaceWithValue(node, replacement);
63 : return Changed(replacement);
64 14561942 : } else if (upper->Is(Type::PlainNumber()) &&
65 536298 : upper->Min() == upper->Max()) {
66 186622 : Node* replacement = jsgraph()->Constant(upper->Min());
67 : ReplaceWithValue(node, replacement);
68 : return Changed(replacement);
69 13932324 : } else if (upper->Is(Type::Undefined())) {
70 1 : Node* replacement = jsgraph()->UndefinedConstant();
71 : ReplaceWithValue(node, replacement);
72 : return Changed(replacement);
73 : }
74 : }
75 : }
76 31468642 : switch (node->opcode()) {
77 : case IrOpcode::kCheckHeapObject:
78 40041 : return ReduceCheckHeapObject(node);
79 : case IrOpcode::kCheckMaps:
80 68915 : return ReduceCheckMaps(node);
81 : case IrOpcode::kCheckNumber:
82 3873 : return ReduceCheckNumber(node);
83 : case IrOpcode::kCheckString:
84 2870 : return ReduceCheckString(node);
85 : case IrOpcode::kLoadField:
86 1074467 : return ReduceLoadField(node);
87 : case IrOpcode::kNumberCeil:
88 : case IrOpcode::kNumberRound:
89 : case IrOpcode::kNumberTrunc:
90 7176 : return ReduceNumberRoundop(node);
91 : case IrOpcode::kNumberFloor:
92 9315 : return ReduceNumberFloor(node);
93 : case IrOpcode::kNumberToUint8Clamped:
94 432 : return ReduceNumberToUint8Clamped(node);
95 : case IrOpcode::kPhi:
96 501078 : return ReducePhi(node);
97 : case IrOpcode::kReferenceEqual:
98 234331 : return ReduceReferenceEqual(node);
99 : case IrOpcode::kSelect:
100 16010 : return ReduceSelect(node);
101 : case IrOpcode::kSpeculativeToNumber:
102 2289 : return ReduceSpeculativeToNumber(node);
103 : default:
104 : break;
105 : }
106 : return NoChange();
107 : }
108 :
109 : namespace {
110 :
111 78850 : MaybeHandle<Map> GetStableMapFromObjectType(Type* object_type) {
112 78850 : if (object_type->IsHeapConstant()) {
113 : Handle<Map> object_map(object_type->AsHeapConstant()->Value()->map());
114 4367 : if (object_map->is_stable()) return object_map;
115 : }
116 : return MaybeHandle<Map>();
117 : }
118 :
119 : } // namespace
120 :
121 40041 : Reduction TypedOptimization::ReduceCheckHeapObject(Node* node) {
122 40041 : Node* const input = NodeProperties::GetValueInput(node, 0);
123 : Type* const input_type = NodeProperties::GetType(input);
124 40041 : if (!input_type->Maybe(Type::SignedSmall())) {
125 10471 : ReplaceWithValue(node, input);
126 : return Replace(input);
127 : }
128 : return NoChange();
129 : }
130 :
131 69306 : Reduction TypedOptimization::ReduceCheckMaps(Node* node) {
132 : // The CheckMaps(o, ...map...) can be eliminated if map is stable,
133 : // o has type Constant(object) and map == object->map, and either
134 : // (1) map cannot transition further, or
135 : // (2) we can add a code dependency on the stability of map
136 : // (to guard the Constant type information).
137 68915 : Node* const object = NodeProperties::GetValueInput(node, 0);
138 : Type* const object_type = NodeProperties::GetType(object);
139 68915 : Node* const effect = NodeProperties::GetEffectInput(node);
140 : Handle<Map> object_map;
141 137830 : if (GetStableMapFromObjectType(object_type).ToHandle(&object_map)) {
142 782 : for (int i = 1; i < node->op()->ValueInputCount(); ++i) {
143 0 : Node* const map = NodeProperties::GetValueInput(node, i);
144 : Type* const map_type = NodeProperties::GetType(map);
145 0 : if (map_type->IsHeapConstant() &&
146 : map_type->AsHeapConstant()->Value().is_identical_to(object_map)) {
147 0 : if (object_map->CanTransition()) {
148 0 : dependencies()->AssumeMapStable(object_map);
149 : }
150 : return Replace(effect);
151 : }
152 : }
153 : }
154 : return NoChange();
155 : }
156 :
157 3873 : Reduction TypedOptimization::ReduceCheckNumber(Node* node) {
158 3873 : Node* const input = NodeProperties::GetValueInput(node, 0);
159 : Type* const input_type = NodeProperties::GetType(input);
160 3873 : if (input_type->Is(Type::Number())) {
161 3378 : ReplaceWithValue(node, input);
162 : return Replace(input);
163 : }
164 : return NoChange();
165 : }
166 :
167 2870 : Reduction TypedOptimization::ReduceCheckString(Node* node) {
168 2870 : Node* const input = NodeProperties::GetValueInput(node, 0);
169 : Type* const input_type = NodeProperties::GetType(input);
170 2870 : if (input_type->Is(Type::String())) {
171 989 : ReplaceWithValue(node, input);
172 : return Replace(input);
173 : }
174 : return NoChange();
175 : }
176 :
177 2149048 : Reduction TypedOptimization::ReduceLoadField(Node* node) {
178 1074467 : Node* const object = NodeProperties::GetValueInput(node, 0);
179 : Type* const object_type = NodeProperties::GetType(object);
180 1074467 : FieldAccess const& access = FieldAccessOf(node->op());
181 1074467 : if (access.base_is_tagged == kTaggedBase &&
182 : access.offset == HeapObject::kMapOffset) {
183 : // We can replace LoadField[Map](o) with map if is stable, and
184 : // o has type Constant(object) and map == object->map, and either
185 : // (1) map cannot transition further, or
186 : // (2) deoptimization is enabled and we can add a code dependency on the
187 : // stability of map (to guard the Constant type information).
188 : Handle<Map> object_map;
189 19870 : if (GetStableMapFromObjectType(object_type).ToHandle(&object_map)) {
190 57 : if (object_map->CanTransition()) {
191 57 : if (flags() & kDeoptimizationEnabled) {
192 57 : dependencies()->AssumeMapStable(object_map);
193 : } else {
194 : return NoChange();
195 : }
196 : }
197 57 : Node* const value = jsgraph()->HeapConstant(object_map);
198 57 : ReplaceWithValue(node, value);
199 : return Replace(value);
200 : }
201 : }
202 : return NoChange();
203 : }
204 :
205 9315 : Reduction TypedOptimization::ReduceNumberFloor(Node* node) {
206 9675 : Node* const input = NodeProperties::GetValueInput(node, 0);
207 : Type* const input_type = NodeProperties::GetType(input);
208 18630 : if (input_type->Is(type_cache_.kIntegerOrMinusZeroOrNaN)) {
209 : return Replace(input);
210 : }
211 18958 : if (input_type->Is(Type::PlainNumber()) &&
212 46 : (input->opcode() == IrOpcode::kNumberDivide ||
213 : input->opcode() == IrOpcode::kSpeculativeNumberDivide)) {
214 321 : Node* const lhs = NodeProperties::GetValueInput(input, 0);
215 : Type* const lhs_type = NodeProperties::GetType(lhs);
216 321 : Node* const rhs = NodeProperties::GetValueInput(input, 1);
217 : Type* const rhs_type = NodeProperties::GetType(rhs);
218 337 : if (lhs_type->Is(Type::Unsigned32()) && rhs_type->Is(Type::Unsigned32())) {
219 : // We can replace
220 : //
221 : // NumberFloor(NumberDivide(lhs: unsigned32,
222 : // rhs: unsigned32)): plain-number
223 : //
224 : // with
225 : //
226 : // NumberToUint32(NumberDivide(lhs, rhs))
227 : //
228 : // and just smash the type of the {lhs} on the {node},
229 : // as the truncated result must be in the same range as
230 : // {lhs} since {rhs} cannot be less than 1 (due to the
231 : // plain-number type constraint on the {node}).
232 16 : NodeProperties::ChangeOp(node, simplified()->NumberToUint32());
233 : NodeProperties::SetType(node, lhs_type);
234 : return Changed(node);
235 : }
236 : }
237 : return NoChange();
238 : }
239 :
240 7176 : Reduction TypedOptimization::ReduceNumberRoundop(Node* node) {
241 7176 : Node* const input = NodeProperties::GetValueInput(node, 0);
242 : Type* const input_type = NodeProperties::GetType(input);
243 14352 : if (input_type->Is(type_cache_.kIntegerOrMinusZeroOrNaN)) {
244 : return Replace(input);
245 : }
246 : return NoChange();
247 : }
248 :
249 432 : Reduction TypedOptimization::ReduceNumberToUint8Clamped(Node* node) {
250 432 : Node* const input = NodeProperties::GetValueInput(node, 0);
251 : Type* const input_type = NodeProperties::GetType(input);
252 864 : if (input_type->Is(type_cache_.kUint8)) {
253 : return Replace(input);
254 : }
255 : return NoChange();
256 : }
257 :
258 501078 : Reduction TypedOptimization::ReducePhi(Node* node) {
259 : // Try to narrow the type of the Phi {node}, which might be more precise now
260 : // after lowering based on types, i.e. a SpeculativeNumberAdd has a more
261 : // precise type than the JSAdd that was in the graph when the Typer was run.
262 : DCHECK_EQ(IrOpcode::kPhi, node->opcode());
263 501078 : int arity = node->op()->ValueInputCount();
264 : Type* type = NodeProperties::GetType(node->InputAt(0));
265 1478634 : for (int i = 1; i < arity; ++i) {
266 : type = Type::Union(type, NodeProperties::GetType(node->InputAt(i)),
267 1955112 : graph()->zone());
268 : }
269 : Type* const node_type = NodeProperties::GetType(node);
270 501078 : if (!node_type->Is(type)) {
271 35529 : type = Type::Intersect(node_type, type, graph()->zone());
272 : NodeProperties::SetType(node, type);
273 : return Changed(node);
274 : }
275 : return NoChange();
276 : }
277 :
278 248442 : Reduction TypedOptimization::ReduceReferenceEqual(Node* node) {
279 : DCHECK_EQ(IrOpcode::kReferenceEqual, node->opcode());
280 234331 : Node* const lhs = NodeProperties::GetValueInput(node, 0);
281 234331 : Node* const rhs = NodeProperties::GetValueInput(node, 1);
282 : Type* const lhs_type = NodeProperties::GetType(lhs);
283 : Type* const rhs_type = NodeProperties::GetType(rhs);
284 234331 : if (!lhs_type->Maybe(rhs_type)) {
285 14111 : return Replace(jsgraph()->FalseConstant());
286 : }
287 : return NoChange();
288 : }
289 :
290 16010 : Reduction TypedOptimization::ReduceSelect(Node* node) {
291 : DCHECK_EQ(IrOpcode::kSelect, node->opcode());
292 16010 : Node* const condition = NodeProperties::GetValueInput(node, 0);
293 : Type* const condition_type = NodeProperties::GetType(condition);
294 16010 : Node* const vtrue = NodeProperties::GetValueInput(node, 1);
295 : Type* const vtrue_type = NodeProperties::GetType(vtrue);
296 16010 : Node* const vfalse = NodeProperties::GetValueInput(node, 2);
297 : Type* const vfalse_type = NodeProperties::GetType(vfalse);
298 32020 : if (condition_type->Is(true_type_)) {
299 : // Select(condition:true, vtrue, vfalse) => vtrue
300 : return Replace(vtrue);
301 : }
302 31806 : if (condition_type->Is(false_type_)) {
303 : // Select(condition:false, vtrue, vfalse) => vfalse
304 : return Replace(vfalse);
305 : }
306 29009 : if (vtrue_type->Is(true_type_) && vfalse_type->Is(false_type_)) {
307 : // Select(condition, vtrue:true, vfalse:false) => condition
308 : return Replace(condition);
309 : }
310 22085 : if (vtrue_type->Is(false_type_) && vfalse_type->Is(true_type_)) {
311 : // Select(condition, vtrue:false, vfalse:true) => BooleanNot(condition)
312 182 : node->TrimInputCount(1);
313 182 : NodeProperties::ChangeOp(node, simplified()->BooleanNot());
314 : return Changed(node);
315 : }
316 : // Try to narrow the type of the Select {node}, which might be more precise
317 : // now after lowering based on types.
318 10049 : Type* type = Type::Union(vtrue_type, vfalse_type, graph()->zone());
319 : Type* const node_type = NodeProperties::GetType(node);
320 10049 : if (!node_type->Is(type)) {
321 0 : type = Type::Intersect(node_type, type, graph()->zone());
322 : NodeProperties::SetType(node, type);
323 : return Changed(node);
324 : }
325 : return NoChange();
326 : }
327 :
328 2289 : Reduction TypedOptimization::ReduceSpeculativeToNumber(Node* node) {
329 : DCHECK_EQ(IrOpcode::kSpeculativeToNumber, node->opcode());
330 2289 : Node* const input = NodeProperties::GetValueInput(node, 0);
331 : Type* const input_type = NodeProperties::GetType(input);
332 2289 : if (input_type->Is(Type::Number())) {
333 : // SpeculativeToNumber(x:number) => x
334 1184 : ReplaceWithValue(node, input);
335 : return Replace(input);
336 : }
337 : return NoChange();
338 : }
339 :
340 0 : Factory* TypedOptimization::factory() const { return isolate()->factory(); }
341 :
342 1814074 : Graph* TypedOptimization::graph() const { return jsgraph()->graph(); }
343 :
344 790966 : Isolate* TypedOptimization::isolate() const { return jsgraph()->isolate(); }
345 :
346 198 : SimplifiedOperatorBuilder* TypedOptimization::simplified() const {
347 198 : return jsgraph()->simplified();
348 : }
349 :
350 : } // namespace compiler
351 : } // namespace internal
352 : } // namespace v8
|