• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/base/optional.h"
8 #include "src/compiler/compilation-dependencies.h"
9 #include "src/compiler/js-graph.h"
10 #include "src/compiler/js-heap-broker.h"
11 #include "src/compiler/node-matchers.h"
12 #include "src/compiler/node-properties.h"
13 #include "src/compiler/simplified-operator.h"
14 #include "src/compiler/type-cache.h"
15 #include "src/isolate-inl.h"
16 
17 namespace v8 {
18 namespace internal {
19 namespace compiler {
20 
TypedOptimization(Editor * editor,CompilationDependencies * dependencies,JSGraph * jsgraph,JSHeapBroker * js_heap_broker)21 TypedOptimization::TypedOptimization(Editor* editor,
22                                      CompilationDependencies* dependencies,
23                                      JSGraph* jsgraph,
24                                      JSHeapBroker* js_heap_broker)
25     : AdvancedReducer(editor),
26       dependencies_(dependencies),
27       jsgraph_(jsgraph),
28       js_heap_broker_(js_heap_broker),
29       true_type_(Type::HeapConstant(js_heap_broker, factory()->true_value(),
30                                     graph()->zone())),
31       false_type_(Type::HeapConstant(js_heap_broker, factory()->false_value(),
32                                      graph()->zone())),
33       type_cache_(TypeCache::Get()) {}
34 
~TypedOptimization()35 TypedOptimization::~TypedOptimization() {}
36 
Reduce(Node * node)37 Reduction TypedOptimization::Reduce(Node* node) {
38   DisallowHeapAccess no_heap_access;
39   switch (node->opcode()) {
40     case IrOpcode::kConvertReceiver:
41       return ReduceConvertReceiver(node);
42     case IrOpcode::kCheckHeapObject:
43       return ReduceCheckHeapObject(node);
44     case IrOpcode::kCheckNotTaggedHole:
45       return ReduceCheckNotTaggedHole(node);
46     case IrOpcode::kCheckMaps:
47       return ReduceCheckMaps(node);
48     case IrOpcode::kCheckNumber:
49       return ReduceCheckNumber(node);
50     case IrOpcode::kCheckString:
51       return ReduceCheckString(node);
52     case IrOpcode::kCheckEqualsInternalizedString:
53       return ReduceCheckEqualsInternalizedString(node);
54     case IrOpcode::kCheckEqualsSymbol:
55       return ReduceCheckEqualsSymbol(node);
56     case IrOpcode::kLoadField:
57       return ReduceLoadField(node);
58     case IrOpcode::kNumberCeil:
59     case IrOpcode::kNumberRound:
60     case IrOpcode::kNumberTrunc:
61       return ReduceNumberRoundop(node);
62     case IrOpcode::kNumberFloor:
63       return ReduceNumberFloor(node);
64     case IrOpcode::kNumberToUint8Clamped:
65       return ReduceNumberToUint8Clamped(node);
66     case IrOpcode::kPhi:
67       return ReducePhi(node);
68     case IrOpcode::kReferenceEqual:
69       return ReduceReferenceEqual(node);
70     case IrOpcode::kStringEqual:
71     case IrOpcode::kStringLessThan:
72     case IrOpcode::kStringLessThanOrEqual:
73       return ReduceStringComparison(node);
74     case IrOpcode::kSameValue:
75       return ReduceSameValue(node);
76     case IrOpcode::kSelect:
77       return ReduceSelect(node);
78     case IrOpcode::kTypeOf:
79       return ReduceTypeOf(node);
80     case IrOpcode::kToBoolean:
81       return ReduceToBoolean(node);
82     case IrOpcode::kSpeculativeToNumber:
83       return ReduceSpeculativeToNumber(node);
84     default:
85       break;
86   }
87   return NoChange();
88 }
89 
90 namespace {
91 
GetStableMapFromObjectType(JSHeapBroker * js_heap_broker,Type object_type)92 base::Optional<MapRef> GetStableMapFromObjectType(JSHeapBroker* js_heap_broker,
93                                                   Type object_type) {
94   if (object_type.IsHeapConstant()) {
95     HeapObjectRef object = object_type.AsHeapConstant()->Ref();
96     MapRef object_map = object.map();
97     if (object_map.is_stable()) return object_map;
98   }
99   return {};
100 }
101 
102 }  // namespace
103 
ReduceConvertReceiver(Node * node)104 Reduction TypedOptimization::ReduceConvertReceiver(Node* node) {
105   Node* const value = NodeProperties::GetValueInput(node, 0);
106   Type const value_type = NodeProperties::GetType(value);
107   Node* const global_proxy = NodeProperties::GetValueInput(node, 1);
108   if (value_type.Is(Type::Receiver())) {
109     ReplaceWithValue(node, value);
110     return Replace(value);
111   } else if (value_type.Is(Type::NullOrUndefined())) {
112     ReplaceWithValue(node, global_proxy);
113     return Replace(global_proxy);
114   }
115   return NoChange();
116 }
117 
ReduceCheckHeapObject(Node * node)118 Reduction TypedOptimization::ReduceCheckHeapObject(Node* node) {
119   Node* const input = NodeProperties::GetValueInput(node, 0);
120   Type const input_type = NodeProperties::GetType(input);
121   if (!input_type.Maybe(Type::SignedSmall())) {
122     ReplaceWithValue(node, input);
123     return Replace(input);
124   }
125   return NoChange();
126 }
127 
ReduceCheckNotTaggedHole(Node * node)128 Reduction TypedOptimization::ReduceCheckNotTaggedHole(Node* node) {
129   Node* const input = NodeProperties::GetValueInput(node, 0);
130   Type const input_type = NodeProperties::GetType(input);
131   if (!input_type.Maybe(Type::Hole())) {
132     ReplaceWithValue(node, input);
133     return Replace(input);
134   }
135   return NoChange();
136 }
137 
ReduceCheckMaps(Node * node)138 Reduction TypedOptimization::ReduceCheckMaps(Node* node) {
139   // The CheckMaps(o, ...map...) can be eliminated if map is stable,
140   // o has type Constant(object) and map == object->map, and either
141   //  (1) map cannot transition further, or
142   //  (2) we can add a code dependency on the stability of map
143   //      (to guard the Constant type information).
144   Node* const object = NodeProperties::GetValueInput(node, 0);
145   Type const object_type = NodeProperties::GetType(object);
146   Node* const effect = NodeProperties::GetEffectInput(node);
147   base::Optional<MapRef> object_map =
148       GetStableMapFromObjectType(js_heap_broker(), object_type);
149   if (object_map.has_value()) {
150     for (int i = 1; i < node->op()->ValueInputCount(); ++i) {
151       Node* const map = NodeProperties::GetValueInput(node, i);
152       Type const map_type = NodeProperties::GetType(map);
153       if (map_type.IsHeapConstant() &&
154           map_type.AsHeapConstant()->Ref().equals(*object_map)) {
155         if (object_map->CanTransition()) {
156           dependencies()->DependOnStableMap(*object_map);
157         }
158         return Replace(effect);
159       }
160     }
161   }
162   return NoChange();
163 }
164 
ReduceCheckNumber(Node * node)165 Reduction TypedOptimization::ReduceCheckNumber(Node* node) {
166   Node* const input = NodeProperties::GetValueInput(node, 0);
167   Type const input_type = NodeProperties::GetType(input);
168   if (input_type.Is(Type::Number())) {
169     ReplaceWithValue(node, input);
170     return Replace(input);
171   }
172   return NoChange();
173 }
174 
ReduceCheckString(Node * node)175 Reduction TypedOptimization::ReduceCheckString(Node* node) {
176   Node* const input = NodeProperties::GetValueInput(node, 0);
177   Type const input_type = NodeProperties::GetType(input);
178   if (input_type.Is(Type::String())) {
179     ReplaceWithValue(node, input);
180     return Replace(input);
181   }
182   return NoChange();
183 }
184 
ReduceCheckEqualsInternalizedString(Node * node)185 Reduction TypedOptimization::ReduceCheckEqualsInternalizedString(Node* node) {
186   Node* const exp = NodeProperties::GetValueInput(node, 0);
187   Type const exp_type = NodeProperties::GetType(exp);
188   Node* const val = NodeProperties::GetValueInput(node, 1);
189   Type const val_type = NodeProperties::GetType(val);
190   Node* const effect = NodeProperties::GetEffectInput(node);
191   if (val_type.Is(exp_type)) return Replace(effect);
192   // TODO(turbofan): Should we also try to optimize the
193   // non-internalized String case for {val} here?
194   return NoChange();
195 }
196 
ReduceCheckEqualsSymbol(Node * node)197 Reduction TypedOptimization::ReduceCheckEqualsSymbol(Node* node) {
198   Node* const exp = NodeProperties::GetValueInput(node, 0);
199   Type const exp_type = NodeProperties::GetType(exp);
200   Node* const val = NodeProperties::GetValueInput(node, 1);
201   Type const val_type = NodeProperties::GetType(val);
202   Node* const effect = NodeProperties::GetEffectInput(node);
203   if (val_type.Is(exp_type)) return Replace(effect);
204   return NoChange();
205 }
206 
ReduceLoadField(Node * node)207 Reduction TypedOptimization::ReduceLoadField(Node* node) {
208   Node* const object = NodeProperties::GetValueInput(node, 0);
209   Type const object_type = NodeProperties::GetType(object);
210   FieldAccess const& access = FieldAccessOf(node->op());
211   if (access.base_is_tagged == kTaggedBase &&
212       access.offset == HeapObject::kMapOffset) {
213     // We can replace LoadField[Map](o) with map if is stable, and
214     // o has type Constant(object) and map == object->map, and either
215     //  (1) map cannot transition further, or
216     //  (2) deoptimization is enabled and we can add a code dependency on the
217     //      stability of map (to guard the Constant type information).
218     base::Optional<MapRef> object_map =
219         GetStableMapFromObjectType(js_heap_broker(), object_type);
220     if (object_map.has_value()) {
221       dependencies()->DependOnStableMap(*object_map);
222       Node* const value = jsgraph()->Constant(*object_map);
223       ReplaceWithValue(node, value);
224       return Replace(value);
225     }
226   }
227   return NoChange();
228 }
229 
ReduceNumberFloor(Node * node)230 Reduction TypedOptimization::ReduceNumberFloor(Node* node) {
231   Node* const input = NodeProperties::GetValueInput(node, 0);
232   Type const input_type = NodeProperties::GetType(input);
233   if (input_type.Is(type_cache_.kIntegerOrMinusZeroOrNaN)) {
234     return Replace(input);
235   }
236   if (input_type.Is(Type::PlainNumber()) &&
237       (input->opcode() == IrOpcode::kNumberDivide ||
238        input->opcode() == IrOpcode::kSpeculativeNumberDivide)) {
239     Node* const lhs = NodeProperties::GetValueInput(input, 0);
240     Type const lhs_type = NodeProperties::GetType(lhs);
241     Node* const rhs = NodeProperties::GetValueInput(input, 1);
242     Type const rhs_type = NodeProperties::GetType(rhs);
243     if (lhs_type.Is(Type::Unsigned32()) && rhs_type.Is(Type::Unsigned32())) {
244       // We can replace
245       //
246       //   NumberFloor(NumberDivide(lhs: unsigned32,
247       //                            rhs: unsigned32)): plain-number
248       //
249       // with
250       //
251       //   NumberToUint32(NumberDivide(lhs, rhs))
252       //
253       // and just smash the type [0...lhs.Max] on the {node},
254       // as the truncated result must be loewr than {lhs}'s maximum
255       // value (note that {rhs} cannot be less than 1 due to the
256       // plain-number type constraint on the {node}).
257       NodeProperties::ChangeOp(node, simplified()->NumberToUint32());
258       NodeProperties::SetType(node,
259                               Type::Range(0, lhs_type.Max(), graph()->zone()));
260       return Changed(node);
261     }
262   }
263   return NoChange();
264 }
265 
ReduceNumberRoundop(Node * node)266 Reduction TypedOptimization::ReduceNumberRoundop(Node* node) {
267   Node* const input = NodeProperties::GetValueInput(node, 0);
268   Type const input_type = NodeProperties::GetType(input);
269   if (input_type.Is(type_cache_.kIntegerOrMinusZeroOrNaN)) {
270     return Replace(input);
271   }
272   return NoChange();
273 }
274 
ReduceNumberToUint8Clamped(Node * node)275 Reduction TypedOptimization::ReduceNumberToUint8Clamped(Node* node) {
276   Node* const input = NodeProperties::GetValueInput(node, 0);
277   Type const input_type = NodeProperties::GetType(input);
278   if (input_type.Is(type_cache_.kUint8)) {
279     return Replace(input);
280   }
281   return NoChange();
282 }
283 
ReducePhi(Node * node)284 Reduction TypedOptimization::ReducePhi(Node* node) {
285   // Try to narrow the type of the Phi {node}, which might be more precise now
286   // after lowering based on types, i.e. a SpeculativeNumberAdd has a more
287   // precise type than the JSAdd that was in the graph when the Typer was run.
288   DCHECK_EQ(IrOpcode::kPhi, node->opcode());
289   int arity = node->op()->ValueInputCount();
290   Type type = NodeProperties::GetType(node->InputAt(0));
291   for (int i = 1; i < arity; ++i) {
292     type = Type::Union(type, NodeProperties::GetType(node->InputAt(i)),
293                        graph()->zone());
294   }
295   Type const node_type = NodeProperties::GetType(node);
296   if (!node_type.Is(type)) {
297     type = Type::Intersect(node_type, type, graph()->zone());
298     NodeProperties::SetType(node, type);
299     return Changed(node);
300   }
301   return NoChange();
302 }
303 
ReduceReferenceEqual(Node * node)304 Reduction TypedOptimization::ReduceReferenceEqual(Node* node) {
305   DCHECK_EQ(IrOpcode::kReferenceEqual, node->opcode());
306   Node* const lhs = NodeProperties::GetValueInput(node, 0);
307   Node* const rhs = NodeProperties::GetValueInput(node, 1);
308   Type const lhs_type = NodeProperties::GetType(lhs);
309   Type const rhs_type = NodeProperties::GetType(rhs);
310   if (!lhs_type.Maybe(rhs_type)) {
311     Node* replacement = jsgraph()->FalseConstant();
312     // Make sure we do not widen the type.
313     if (NodeProperties::GetType(replacement)
314             .Is(NodeProperties::GetType(node))) {
315       return Replace(jsgraph()->FalseConstant());
316     }
317   }
318   return NoChange();
319 }
320 
NumberComparisonFor(const Operator * op)321 const Operator* TypedOptimization::NumberComparisonFor(const Operator* op) {
322   switch (op->opcode()) {
323     case IrOpcode::kStringEqual:
324       return simplified()->NumberEqual();
325     case IrOpcode::kStringLessThan:
326       return simplified()->NumberLessThan();
327     case IrOpcode::kStringLessThanOrEqual:
328       return simplified()->NumberLessThanOrEqual();
329     default:
330       break;
331   }
332   UNREACHABLE();
333 }
334 
335 Reduction TypedOptimization::
TryReduceStringComparisonOfStringFromSingleCharCodeToConstant(Node * comparison,const StringRef & string,bool inverted)336     TryReduceStringComparisonOfStringFromSingleCharCodeToConstant(
337         Node* comparison, const StringRef& string, bool inverted) {
338   switch (comparison->opcode()) {
339     case IrOpcode::kStringEqual:
340       if (string.length() != 1) {
341         // String.fromCharCode(x) always has length 1.
342         return Replace(jsgraph()->BooleanConstant(false));
343       }
344       break;
345     case IrOpcode::kStringLessThan:
346       V8_FALLTHROUGH;
347     case IrOpcode::kStringLessThanOrEqual:
348       if (string.length() == 0) {
349         // String.fromCharCode(x) <= "" is always false,
350         // "" < String.fromCharCode(x) is always true.
351         return Replace(jsgraph()->BooleanConstant(inverted));
352       }
353       break;
354     default:
355       UNREACHABLE();
356   }
357   return NoChange();
358 }
359 
360 // Try to reduces a string comparison of the form
361 // String.fromCharCode(x) {comparison} {constant} if inverted is false,
362 // and {constant} {comparison} String.fromCharCode(x) if inverted is true.
363 Reduction
TryReduceStringComparisonOfStringFromSingleCharCode(Node * comparison,Node * from_char_code,Type constant_type,bool inverted)364 TypedOptimization::TryReduceStringComparisonOfStringFromSingleCharCode(
365     Node* comparison, Node* from_char_code, Type constant_type, bool inverted) {
366   DCHECK_EQ(IrOpcode::kStringFromSingleCharCode, from_char_code->opcode());
367 
368   if (!constant_type.IsHeapConstant()) return NoChange();
369   ObjectRef constant = constant_type.AsHeapConstant()->Ref();
370 
371   if (!constant.IsString()) return NoChange();
372   StringRef string = constant.AsString();
373 
374   // Check if comparison can be resolved statically.
375   Reduction red = TryReduceStringComparisonOfStringFromSingleCharCodeToConstant(
376       comparison, string, inverted);
377   if (red.Changed()) return red;
378 
379   const Operator* comparison_op = NumberComparisonFor(comparison->op());
380   Node* from_char_code_repl = NodeProperties::GetValueInput(from_char_code, 0);
381   Type from_char_code_repl_type = NodeProperties::GetType(from_char_code_repl);
382   if (!from_char_code_repl_type.Is(type_cache_.kUint16)) {
383     // Convert to signed int32 to satisfy type of {NumberBitwiseAnd}.
384     from_char_code_repl =
385         graph()->NewNode(simplified()->NumberToInt32(), from_char_code_repl);
386     from_char_code_repl = graph()->NewNode(
387         simplified()->NumberBitwiseAnd(), from_char_code_repl,
388         jsgraph()->Constant(std::numeric_limits<uint16_t>::max()));
389   }
390   Node* constant_repl = jsgraph()->Constant(string.GetFirstChar());
391 
392   Node* number_comparison = nullptr;
393   if (inverted) {
394     // "x..." <= String.fromCharCode(z) is true if x < z.
395     if (string.length() > 1 &&
396         comparison->opcode() == IrOpcode::kStringLessThanOrEqual) {
397       comparison_op = simplified()->NumberLessThan();
398     }
399     number_comparison =
400         graph()->NewNode(comparison_op, constant_repl, from_char_code_repl);
401   } else {
402     // String.fromCharCode(z) < "x..." is true if z <= x.
403     if (string.length() > 1 &&
404         comparison->opcode() == IrOpcode::kStringLessThan) {
405       comparison_op = simplified()->NumberLessThanOrEqual();
406     }
407     number_comparison =
408         graph()->NewNode(comparison_op, from_char_code_repl, constant_repl);
409   }
410   ReplaceWithValue(comparison, number_comparison);
411   return Replace(number_comparison);
412 }
413 
ReduceStringComparison(Node * node)414 Reduction TypedOptimization::ReduceStringComparison(Node* node) {
415   DCHECK(IrOpcode::kStringEqual == node->opcode() ||
416          IrOpcode::kStringLessThan == node->opcode() ||
417          IrOpcode::kStringLessThanOrEqual == node->opcode());
418   Node* const lhs = NodeProperties::GetValueInput(node, 0);
419   Node* const rhs = NodeProperties::GetValueInput(node, 1);
420   Type lhs_type = NodeProperties::GetType(lhs);
421   Type rhs_type = NodeProperties::GetType(rhs);
422   if (lhs->opcode() == IrOpcode::kStringFromSingleCharCode) {
423     if (rhs->opcode() == IrOpcode::kStringFromSingleCharCode) {
424       Node* left = NodeProperties::GetValueInput(lhs, 0);
425       Node* right = NodeProperties::GetValueInput(rhs, 0);
426       Type left_type = NodeProperties::GetType(left);
427       Type right_type = NodeProperties::GetType(right);
428       if (!left_type.Is(type_cache_.kUint16)) {
429         // Convert to signed int32 to satisfy type of {NumberBitwiseAnd}.
430         left = graph()->NewNode(simplified()->NumberToInt32(), left);
431         left = graph()->NewNode(
432             simplified()->NumberBitwiseAnd(), left,
433             jsgraph()->Constant(std::numeric_limits<uint16_t>::max()));
434       }
435       if (!right_type.Is(type_cache_.kUint16)) {
436         // Convert to signed int32 to satisfy type of {NumberBitwiseAnd}.
437         right = graph()->NewNode(simplified()->NumberToInt32(), right);
438         right = graph()->NewNode(
439             simplified()->NumberBitwiseAnd(), right,
440             jsgraph()->Constant(std::numeric_limits<uint16_t>::max()));
441       }
442       Node* equal =
443           graph()->NewNode(NumberComparisonFor(node->op()), left, right);
444       ReplaceWithValue(node, equal);
445       return Replace(equal);
446     } else {
447       return TryReduceStringComparisonOfStringFromSingleCharCode(
448           node, lhs, rhs_type, false);
449     }
450   } else if (rhs->opcode() == IrOpcode::kStringFromSingleCharCode) {
451     return TryReduceStringComparisonOfStringFromSingleCharCode(node, rhs,
452                                                                lhs_type, true);
453   }
454   return NoChange();
455 }
456 
ReduceSameValue(Node * node)457 Reduction TypedOptimization::ReduceSameValue(Node* node) {
458   DCHECK_EQ(IrOpcode::kSameValue, node->opcode());
459   Node* const lhs = NodeProperties::GetValueInput(node, 0);
460   Node* const rhs = NodeProperties::GetValueInput(node, 1);
461   Type const lhs_type = NodeProperties::GetType(lhs);
462   Type const rhs_type = NodeProperties::GetType(rhs);
463   if (lhs == rhs) {
464     // SameValue(x,x) => #true
465     return Replace(jsgraph()->TrueConstant());
466   } else if (lhs_type.Is(Type::Unique()) && rhs_type.Is(Type::Unique())) {
467     // SameValue(x:unique,y:unique) => ReferenceEqual(x,y)
468     NodeProperties::ChangeOp(node, simplified()->ReferenceEqual());
469     return Changed(node);
470   } else if (lhs_type.Is(Type::String()) && rhs_type.Is(Type::String())) {
471     // SameValue(x:string,y:string) => StringEqual(x,y)
472     NodeProperties::ChangeOp(node, simplified()->StringEqual());
473     return Changed(node);
474   } else if (lhs_type.Is(Type::MinusZero())) {
475     // SameValue(x:minus-zero,y) => ObjectIsMinusZero(y)
476     node->RemoveInput(0);
477     NodeProperties::ChangeOp(node, simplified()->ObjectIsMinusZero());
478     return Changed(node);
479   } else if (rhs_type.Is(Type::MinusZero())) {
480     // SameValue(x,y:minus-zero) => ObjectIsMinusZero(x)
481     node->RemoveInput(1);
482     NodeProperties::ChangeOp(node, simplified()->ObjectIsMinusZero());
483     return Changed(node);
484   } else if (lhs_type.Is(Type::NaN())) {
485     // SameValue(x:nan,y) => ObjectIsNaN(y)
486     node->RemoveInput(0);
487     NodeProperties::ChangeOp(node, simplified()->ObjectIsNaN());
488     return Changed(node);
489   } else if (rhs_type.Is(Type::NaN())) {
490     // SameValue(x,y:nan) => ObjectIsNaN(x)
491     node->RemoveInput(1);
492     NodeProperties::ChangeOp(node, simplified()->ObjectIsNaN());
493     return Changed(node);
494   } else if (lhs_type.Is(Type::PlainNumber()) &&
495              rhs_type.Is(Type::PlainNumber())) {
496     // SameValue(x:plain-number,y:plain-number) => NumberEqual(x,y)
497     NodeProperties::ChangeOp(node, simplified()->NumberEqual());
498     return Changed(node);
499   }
500   return NoChange();
501 }
502 
ReduceSelect(Node * node)503 Reduction TypedOptimization::ReduceSelect(Node* node) {
504   DCHECK_EQ(IrOpcode::kSelect, node->opcode());
505   Node* const condition = NodeProperties::GetValueInput(node, 0);
506   Type const condition_type = NodeProperties::GetType(condition);
507   Node* const vtrue = NodeProperties::GetValueInput(node, 1);
508   Type const vtrue_type = NodeProperties::GetType(vtrue);
509   Node* const vfalse = NodeProperties::GetValueInput(node, 2);
510   Type const vfalse_type = NodeProperties::GetType(vfalse);
511   if (condition_type.Is(true_type_)) {
512     // Select(condition:true, vtrue, vfalse) => vtrue
513     return Replace(vtrue);
514   }
515   if (condition_type.Is(false_type_)) {
516     // Select(condition:false, vtrue, vfalse) => vfalse
517     return Replace(vfalse);
518   }
519   if (vtrue_type.Is(true_type_) && vfalse_type.Is(false_type_)) {
520     // Select(condition, vtrue:true, vfalse:false) => condition
521     return Replace(condition);
522   }
523   if (vtrue_type.Is(false_type_) && vfalse_type.Is(true_type_)) {
524     // Select(condition, vtrue:false, vfalse:true) => BooleanNot(condition)
525     node->TrimInputCount(1);
526     NodeProperties::ChangeOp(node, simplified()->BooleanNot());
527     return Changed(node);
528   }
529   // Try to narrow the type of the Select {node}, which might be more precise
530   // now after lowering based on types.
531   Type type = Type::Union(vtrue_type, vfalse_type, graph()->zone());
532   Type const node_type = NodeProperties::GetType(node);
533   if (!node_type.Is(type)) {
534     type = Type::Intersect(node_type, type, graph()->zone());
535     NodeProperties::SetType(node, type);
536     return Changed(node);
537   }
538   return NoChange();
539 }
540 
ReduceSpeculativeToNumber(Node * node)541 Reduction TypedOptimization::ReduceSpeculativeToNumber(Node* node) {
542   DCHECK_EQ(IrOpcode::kSpeculativeToNumber, node->opcode());
543   Node* const input = NodeProperties::GetValueInput(node, 0);
544   Type const input_type = NodeProperties::GetType(input);
545   if (input_type.Is(Type::Number())) {
546     // SpeculativeToNumber(x:number) => x
547     ReplaceWithValue(node, input);
548     return Replace(input);
549   }
550   return NoChange();
551 }
552 
ReduceTypeOf(Node * node)553 Reduction TypedOptimization::ReduceTypeOf(Node* node) {
554   Node* const input = node->InputAt(0);
555   Type const type = NodeProperties::GetType(input);
556   Factory* const f = factory();
557   if (type.Is(Type::Boolean())) {
558     return Replace(
559         jsgraph()->Constant(ObjectRef(js_heap_broker(), f->boolean_string())));
560   } else if (type.Is(Type::Number())) {
561     return Replace(
562         jsgraph()->Constant(ObjectRef(js_heap_broker(), f->number_string())));
563   } else if (type.Is(Type::String())) {
564     return Replace(
565         jsgraph()->Constant(ObjectRef(js_heap_broker(), f->string_string())));
566   } else if (type.Is(Type::BigInt())) {
567     return Replace(
568         jsgraph()->Constant(ObjectRef(js_heap_broker(), f->bigint_string())));
569   } else if (type.Is(Type::Symbol())) {
570     return Replace(
571         jsgraph()->Constant(ObjectRef(js_heap_broker(), f->symbol_string())));
572   } else if (type.Is(Type::OtherUndetectableOrUndefined())) {
573     return Replace(jsgraph()->Constant(
574         ObjectRef(js_heap_broker(), f->undefined_string())));
575   } else if (type.Is(Type::NonCallableOrNull())) {
576     return Replace(
577         jsgraph()->Constant(ObjectRef(js_heap_broker(), f->object_string())));
578   } else if (type.Is(Type::Function())) {
579     return Replace(
580         jsgraph()->Constant(ObjectRef(js_heap_broker(), f->function_string())));
581   } else if (type.IsHeapConstant()) {
582     return Replace(jsgraph()->Constant(type.AsHeapConstant()->Ref().TypeOf()));
583   }
584   return NoChange();
585 }
586 
ReduceToBoolean(Node * node)587 Reduction TypedOptimization::ReduceToBoolean(Node* node) {
588   Node* const input = node->InputAt(0);
589   Type const input_type = NodeProperties::GetType(input);
590   if (input_type.Is(Type::Boolean())) {
591     // ToBoolean(x:boolean) => x
592     return Replace(input);
593   } else if (input_type.Is(Type::OrderedNumber())) {
594     // SToBoolean(x:ordered-number) => BooleanNot(NumberEqual(x,#0))
595     node->ReplaceInput(0, graph()->NewNode(simplified()->NumberEqual(), input,
596                                            jsgraph()->ZeroConstant()));
597     node->TrimInputCount(1);
598     NodeProperties::ChangeOp(node, simplified()->BooleanNot());
599     return Changed(node);
600   } else if (input_type.Is(Type::Number())) {
601     // ToBoolean(x:number) => NumberToBoolean(x)
602     node->TrimInputCount(1);
603     NodeProperties::ChangeOp(node, simplified()->NumberToBoolean());
604     return Changed(node);
605   } else if (input_type.Is(Type::DetectableReceiverOrNull())) {
606     // ToBoolean(x:detectable receiver \/ null)
607     //   => BooleanNot(ReferenceEqual(x,#null))
608     node->ReplaceInput(0, graph()->NewNode(simplified()->ReferenceEqual(),
609                                            input, jsgraph()->NullConstant()));
610     node->TrimInputCount(1);
611     NodeProperties::ChangeOp(node, simplified()->BooleanNot());
612     return Changed(node);
613   } else if (input_type.Is(Type::ReceiverOrNullOrUndefined())) {
614     // ToBoolean(x:receiver \/ null \/ undefined)
615     //   => BooleanNot(ObjectIsUndetectable(x))
616     node->ReplaceInput(
617         0, graph()->NewNode(simplified()->ObjectIsUndetectable(), input));
618     node->TrimInputCount(1);
619     NodeProperties::ChangeOp(node, simplified()->BooleanNot());
620     return Changed(node);
621   } else if (input_type.Is(Type::String())) {
622     // ToBoolean(x:string) => BooleanNot(ReferenceEqual(x,""))
623     node->ReplaceInput(0,
624                        graph()->NewNode(simplified()->ReferenceEqual(), input,
625                                         jsgraph()->EmptyStringConstant()));
626     node->TrimInputCount(1);
627     NodeProperties::ChangeOp(node, simplified()->BooleanNot());
628     return Changed(node);
629   }
630   return NoChange();
631 }
632 
factory() const633 Factory* TypedOptimization::factory() const { return isolate()->factory(); }
634 
graph() const635 Graph* TypedOptimization::graph() const { return jsgraph()->graph(); }
636 
isolate() const637 Isolate* TypedOptimization::isolate() const { return jsgraph()->isolate(); }
638 
simplified() const639 SimplifiedOperatorBuilder* TypedOptimization::simplified() const {
640   return jsgraph()->simplified();
641 }
642 
643 }  // namespace compiler
644 }  // namespace internal
645 }  // namespace v8
646