5 #include "src/compiler/typed-optimization.h" 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" 21 TypedOptimization::TypedOptimization(Editor* editor,
22 CompilationDependencies* dependencies,
23 JSGraph* jsgraph, JSHeapBroker* broker)
24 : AdvancedReducer(editor),
25 dependencies_(dependencies),
29 Type::HeapConstant(broker, factory()->true_value(), graph()->zone())),
30 false_type_(
Type::HeapConstant(broker, factory()->false_value(),
32 type_cache_(TypeCache::Get()) {}
34 TypedOptimization::~TypedOptimization() =
default;
36 Reduction TypedOptimization::Reduce(Node* node) {
37 DisallowHeapAccess no_heap_access;
38 switch (node->opcode()) {
39 case IrOpcode::kConvertReceiver:
40 return ReduceConvertReceiver(node);
41 case IrOpcode::kCheckHeapObject:
42 return ReduceCheckHeapObject(node);
43 case IrOpcode::kCheckNotTaggedHole:
44 return ReduceCheckNotTaggedHole(node);
45 case IrOpcode::kCheckMaps:
46 return ReduceCheckMaps(node);
47 case IrOpcode::kCheckNumber:
48 return ReduceCheckNumber(node);
49 case IrOpcode::kCheckString:
50 return ReduceCheckString(node);
51 case IrOpcode::kCheckEqualsInternalizedString:
52 return ReduceCheckEqualsInternalizedString(node);
53 case IrOpcode::kCheckEqualsSymbol:
54 return ReduceCheckEqualsSymbol(node);
55 case IrOpcode::kLoadField:
56 return ReduceLoadField(node);
57 case IrOpcode::kNumberCeil:
58 case IrOpcode::kNumberRound:
59 case IrOpcode::kNumberTrunc:
60 return ReduceNumberRoundop(node);
61 case IrOpcode::kNumberFloor:
62 return ReduceNumberFloor(node);
63 case IrOpcode::kNumberSilenceNaN:
64 return ReduceNumberSilenceNaN(node);
65 case IrOpcode::kNumberToUint8Clamped:
66 return ReduceNumberToUint8Clamped(node);
68 return ReducePhi(node);
69 case IrOpcode::kReferenceEqual:
70 return ReduceReferenceEqual(node);
71 case IrOpcode::kStringEqual:
72 case IrOpcode::kStringLessThan:
73 case IrOpcode::kStringLessThanOrEqual:
74 return ReduceStringComparison(node);
75 case IrOpcode::kStringLength:
76 return ReduceStringLength(node);
77 case IrOpcode::kSameValue:
78 return ReduceSameValue(node);
79 case IrOpcode::kSelect:
80 return ReduceSelect(node);
81 case IrOpcode::kTypeOf:
82 return ReduceTypeOf(node);
83 case IrOpcode::kToBoolean:
84 return ReduceToBoolean(node);
85 case IrOpcode::kSpeculativeToNumber:
86 return ReduceSpeculativeToNumber(node);
87 case IrOpcode::kSpeculativeNumberAdd:
88 return ReduceSpeculativeNumberAdd(node);
89 case IrOpcode::kSpeculativeNumberSubtract:
90 case IrOpcode::kSpeculativeNumberMultiply:
91 case IrOpcode::kSpeculativeNumberDivide:
92 case IrOpcode::kSpeculativeNumberModulus:
93 return ReduceSpeculativeNumberBinop(node);
94 case IrOpcode::kSpeculativeNumberEqual:
95 case IrOpcode::kSpeculativeNumberLessThan:
96 case IrOpcode::kSpeculativeNumberLessThanOrEqual:
97 return ReduceSpeculativeNumberComparison(node);
106 base::Optional<MapRef> GetStableMapFromObjectType(JSHeapBroker* broker,
108 if (object_type.IsHeapConstant()) {
109 HeapObjectRef
object = object_type.AsHeapConstant()->Ref();
110 MapRef object_map =
object.map();
111 if (object_map.is_stable())
return object_map;
118 Reduction TypedOptimization::ReduceConvertReceiver(Node* node) {
119 Node*
const value = NodeProperties::GetValueInput(node, 0);
120 Type const value_type = NodeProperties::GetType(value);
121 Node*
const global_proxy = NodeProperties::GetValueInput(node, 1);
122 if (value_type.Is(Type::Receiver())) {
123 ReplaceWithValue(node, value);
124 return Replace(value);
125 }
else if (value_type.Is(Type::NullOrUndefined())) {
126 ReplaceWithValue(node, global_proxy);
127 return Replace(global_proxy);
132 Reduction TypedOptimization::ReduceCheckHeapObject(Node* node) {
133 Node*
const input = NodeProperties::GetValueInput(node, 0);
134 Type const input_type = NodeProperties::GetType(input);
135 if (!input_type.Maybe(Type::SignedSmall())) {
136 ReplaceWithValue(node, input);
137 return Replace(input);
142 Reduction TypedOptimization::ReduceCheckNotTaggedHole(Node* node) {
143 Node*
const input = NodeProperties::GetValueInput(node, 0);
144 Type const input_type = NodeProperties::GetType(input);
145 if (!input_type.Maybe(Type::Hole())) {
146 ReplaceWithValue(node, input);
147 return Replace(input);
152 Reduction TypedOptimization::ReduceCheckMaps(Node* node) {
158 Node*
const object = NodeProperties::GetValueInput(node, 0);
159 Type const object_type = NodeProperties::GetType(
object);
160 Node*
const effect = NodeProperties::GetEffectInput(node);
161 base::Optional<MapRef> object_map =
162 GetStableMapFromObjectType(broker(), object_type);
163 if (object_map.has_value()) {
164 for (
int i = 1;
i < node->op()->ValueInputCount(); ++
i) {
165 Node*
const map = NodeProperties::GetValueInput(node,
i);
166 Type const map_type = NodeProperties::GetType(map);
167 if (map_type.IsHeapConstant() &&
168 map_type.AsHeapConstant()->Ref().equals(*object_map)) {
169 if (object_map->CanTransition()) {
170 dependencies()->DependOnStableMap(*object_map);
172 return Replace(effect);
179 Reduction TypedOptimization::ReduceCheckNumber(Node* node) {
180 Node*
const input = NodeProperties::GetValueInput(node, 0);
181 Type const input_type = NodeProperties::GetType(input);
182 if (input_type.Is(Type::Number())) {
183 ReplaceWithValue(node, input);
184 return Replace(input);
189 Reduction TypedOptimization::ReduceCheckString(Node* node) {
190 Node*
const input = NodeProperties::GetValueInput(node, 0);
191 Type const input_type = NodeProperties::GetType(input);
192 if (input_type.Is(Type::String())) {
193 ReplaceWithValue(node, input);
194 return Replace(input);
199 Reduction TypedOptimization::ReduceCheckEqualsInternalizedString(Node* node) {
200 Node*
const exp = NodeProperties::GetValueInput(node, 0);
201 Type const exp_type = NodeProperties::GetType(exp);
202 Node*
const val = NodeProperties::GetValueInput(node, 1);
203 Type const val_type = NodeProperties::GetType(val);
204 Node*
const effect = NodeProperties::GetEffectInput(node);
205 if (val_type.Is(exp_type))
return Replace(effect);
211 Reduction TypedOptimization::ReduceCheckEqualsSymbol(Node* node) {
212 Node*
const exp = NodeProperties::GetValueInput(node, 0);
213 Type const exp_type = NodeProperties::GetType(exp);
214 Node*
const val = NodeProperties::GetValueInput(node, 1);
215 Type const val_type = NodeProperties::GetType(val);
216 Node*
const effect = NodeProperties::GetEffectInput(node);
217 if (val_type.Is(exp_type))
return Replace(effect);
221 Reduction TypedOptimization::ReduceLoadField(Node* node) {
222 Node*
const object = NodeProperties::GetValueInput(node, 0);
223 Type const object_type = NodeProperties::GetType(
object);
224 FieldAccess
const& access = FieldAccessOf(node->op());
225 if (access.base_is_tagged == kTaggedBase &&
226 access.offset == HeapObject::kMapOffset) {
232 base::Optional<MapRef> object_map =
233 GetStableMapFromObjectType(broker(), object_type);
234 if (object_map.has_value()) {
235 dependencies()->DependOnStableMap(*object_map);
236 Node*
const value = jsgraph()->Constant(*object_map);
237 ReplaceWithValue(node, value);
238 return Replace(value);
244 Reduction TypedOptimization::ReduceNumberFloor(Node* node) {
245 Node*
const input = NodeProperties::GetValueInput(node, 0);
246 Type const input_type = NodeProperties::GetType(input);
247 if (input_type.Is(type_cache_.kIntegerOrMinusZeroOrNaN)) {
248 return Replace(input);
250 if (input_type.Is(Type::PlainNumber()) &&
251 (input->opcode() == IrOpcode::kNumberDivide ||
252 input->opcode() == IrOpcode::kSpeculativeNumberDivide)) {
253 Node*
const lhs = NodeProperties::GetValueInput(input, 0);
254 Type const lhs_type = NodeProperties::GetType(lhs);
255 Node*
const rhs = NodeProperties::GetValueInput(input, 1);
256 Type const rhs_type = NodeProperties::GetType(rhs);
257 if (lhs_type.Is(Type::Unsigned32()) && rhs_type.Is(Type::Unsigned32())) {
271 NodeProperties::ChangeOp(node, simplified()->NumberToUint32());
272 NodeProperties::SetType(node,
273 Type::Range(0, lhs_type.Max(), graph()->zone()));
274 return Changed(node);
280 Reduction TypedOptimization::ReduceNumberRoundop(Node* node) {
281 Node*
const input = NodeProperties::GetValueInput(node, 0);
282 Type const input_type = NodeProperties::GetType(input);
283 if (input_type.Is(type_cache_.kIntegerOrMinusZeroOrNaN)) {
284 return Replace(input);
289 Reduction TypedOptimization::ReduceNumberSilenceNaN(Node* node) {
290 Node*
const input = NodeProperties::GetValueInput(node, 0);
291 Type const input_type = NodeProperties::GetType(input);
292 if (input_type.Is(Type::OrderedNumber())) {
293 return Replace(input);
298 Reduction TypedOptimization::ReduceNumberToUint8Clamped(Node* node) {
299 Node*
const input = NodeProperties::GetValueInput(node, 0);
300 Type const input_type = NodeProperties::GetType(input);
301 if (input_type.Is(type_cache_.kUint8)) {
302 return Replace(input);
307 Reduction TypedOptimization::ReducePhi(Node* node) {
311 DCHECK_EQ(IrOpcode::kPhi, node->opcode());
312 int arity = node->op()->ValueInputCount();
313 Type type = NodeProperties::GetType(node->InputAt(0));
314 for (
int i = 1;
i < arity; ++
i) {
315 type = Type::Union(type, NodeProperties::GetType(node->InputAt(
i)),
318 Type const node_type = NodeProperties::GetType(node);
319 if (!node_type.Is(type)) {
320 type = Type::Intersect(node_type, type, graph()->zone());
321 NodeProperties::SetType(node, type);
322 return Changed(node);
327 Reduction TypedOptimization::ReduceReferenceEqual(Node* node) {
328 DCHECK_EQ(IrOpcode::kReferenceEqual, node->opcode());
329 Node*
const lhs = NodeProperties::GetValueInput(node, 0);
330 Node*
const rhs = NodeProperties::GetValueInput(node, 1);
331 Type const lhs_type = NodeProperties::GetType(lhs);
332 Type const rhs_type = NodeProperties::GetType(rhs);
333 if (!lhs_type.Maybe(rhs_type)) {
334 Node* replacement = jsgraph()->FalseConstant();
336 if (NodeProperties::GetType(replacement)
337 .Is(NodeProperties::GetType(node))) {
338 return Replace(jsgraph()->FalseConstant());
344 const Operator* TypedOptimization::NumberComparisonFor(
const Operator* op) {
345 switch (op->opcode()) {
346 case IrOpcode::kStringEqual:
347 return simplified()->NumberEqual();
348 case IrOpcode::kStringLessThan:
349 return simplified()->NumberLessThan();
350 case IrOpcode::kStringLessThanOrEqual:
351 return simplified()->NumberLessThanOrEqual();
358 Reduction TypedOptimization::
359 TryReduceStringComparisonOfStringFromSingleCharCodeToConstant(
360 Node* comparison,
const StringRef&
string,
bool inverted) {
361 switch (comparison->opcode()) {
362 case IrOpcode::kStringEqual:
363 if (
string.length() != 1) {
365 return Replace(jsgraph()->BooleanConstant(
false));
368 case IrOpcode::kStringLessThan:
370 case IrOpcode::kStringLessThanOrEqual:
371 if (
string.length() == 0) {
374 return Replace(jsgraph()->BooleanConstant(inverted));
387 TypedOptimization::TryReduceStringComparisonOfStringFromSingleCharCode(
388 Node* comparison, Node* from_char_code,
Type constant_type,
bool inverted) {
389 DCHECK_EQ(IrOpcode::kStringFromSingleCharCode, from_char_code->opcode());
391 if (!constant_type.IsHeapConstant())
return NoChange();
392 ObjectRef constant = constant_type.AsHeapConstant()->Ref();
394 if (!constant.IsString())
return NoChange();
395 StringRef
string = constant.AsString();
398 Reduction red = TryReduceStringComparisonOfStringFromSingleCharCodeToConstant(
399 comparison,
string, inverted);
400 if (red.Changed())
return red;
402 const Operator* comparison_op = NumberComparisonFor(comparison->op());
403 Node* from_char_code_repl = NodeProperties::GetValueInput(from_char_code, 0);
404 Type from_char_code_repl_type = NodeProperties::GetType(from_char_code_repl);
405 if (!from_char_code_repl_type.Is(type_cache_.kUint16)) {
407 from_char_code_repl =
408 graph()->NewNode(simplified()->NumberToInt32(), from_char_code_repl);
409 from_char_code_repl = graph()->NewNode(
410 simplified()->NumberBitwiseAnd(), from_char_code_repl,
411 jsgraph()->Constant(std::numeric_limits<uint16_t>::max()));
413 Node* constant_repl = jsgraph()->Constant(
string.GetFirstChar());
415 Node* number_comparison =
nullptr;
418 if (
string.length() > 1 &&
419 comparison->opcode() == IrOpcode::kStringLessThanOrEqual) {
420 comparison_op = simplified()->NumberLessThan();
423 graph()->NewNode(comparison_op, constant_repl, from_char_code_repl);
426 if (
string.length() > 1 &&
427 comparison->opcode() == IrOpcode::kStringLessThan) {
428 comparison_op = simplified()->NumberLessThanOrEqual();
431 graph()->NewNode(comparison_op, from_char_code_repl, constant_repl);
433 ReplaceWithValue(comparison, number_comparison);
434 return Replace(number_comparison);
437 Reduction TypedOptimization::ReduceStringComparison(Node* node) {
438 DCHECK(IrOpcode::kStringEqual == node->opcode() ||
439 IrOpcode::kStringLessThan == node->opcode() ||
440 IrOpcode::kStringLessThanOrEqual == node->opcode());
441 Node*
const lhs = NodeProperties::GetValueInput(node, 0);
442 Node*
const rhs = NodeProperties::GetValueInput(node, 1);
443 Type lhs_type = NodeProperties::GetType(lhs);
444 Type rhs_type = NodeProperties::GetType(rhs);
445 if (lhs->opcode() == IrOpcode::kStringFromSingleCharCode) {
446 if (rhs->opcode() == IrOpcode::kStringFromSingleCharCode) {
447 Node* left = NodeProperties::GetValueInput(lhs, 0);
448 Node* right = NodeProperties::GetValueInput(rhs, 0);
449 Type left_type = NodeProperties::GetType(left);
450 Type right_type = NodeProperties::GetType(right);
451 if (!left_type.Is(type_cache_.kUint16)) {
453 left = graph()->NewNode(simplified()->NumberToInt32(), left);
454 left = graph()->NewNode(
455 simplified()->NumberBitwiseAnd(), left,
456 jsgraph()->Constant(std::numeric_limits<uint16_t>::max()));
458 if (!right_type.Is(type_cache_.kUint16)) {
460 right = graph()->NewNode(simplified()->NumberToInt32(), right);
461 right = graph()->NewNode(
462 simplified()->NumberBitwiseAnd(), right,
463 jsgraph()->Constant(std::numeric_limits<uint16_t>::max()));
466 graph()->NewNode(NumberComparisonFor(node->op()), left, right);
467 ReplaceWithValue(node, equal);
468 return Replace(equal);
470 return TryReduceStringComparisonOfStringFromSingleCharCode(
471 node, lhs, rhs_type,
false);
473 }
else if (rhs->opcode() == IrOpcode::kStringFromSingleCharCode) {
474 return TryReduceStringComparisonOfStringFromSingleCharCode(node, rhs,
480 Reduction TypedOptimization::ReduceStringLength(Node* node) {
481 DCHECK_EQ(IrOpcode::kStringLength, node->opcode());
482 Node*
const input = NodeProperties::GetValueInput(node, 0);
483 switch (input->opcode()) {
484 case IrOpcode::kHeapConstant: {
486 HeapObjectMatcher m(input);
487 if (m.Ref(broker()).IsString()) {
488 uint32_t const length = m.Ref(broker()).AsString().length();
489 Node* value = jsgraph()->Constant(length);
490 return Replace(value);
494 case IrOpcode::kStringConcat: {
496 return Replace(input->InputAt(0));
504 Reduction TypedOptimization::ReduceSameValue(Node* node) {
505 DCHECK_EQ(IrOpcode::kSameValue, node->opcode());
506 Node*
const lhs = NodeProperties::GetValueInput(node, 0);
507 Node*
const rhs = NodeProperties::GetValueInput(node, 1);
508 Type const lhs_type = NodeProperties::GetType(lhs);
509 Type const rhs_type = NodeProperties::GetType(rhs);
512 return Replace(jsgraph()->TrueConstant());
513 }
else if (lhs_type.Is(Type::Unique()) && rhs_type.Is(Type::Unique())) {
515 NodeProperties::ChangeOp(node, simplified()->ReferenceEqual());
516 return Changed(node);
517 }
else if (lhs_type.Is(Type::String()) && rhs_type.Is(Type::String())) {
519 NodeProperties::ChangeOp(node, simplified()->StringEqual());
520 return Changed(node);
521 }
else if (lhs_type.Is(Type::MinusZero())) {
523 node->RemoveInput(0);
524 NodeProperties::ChangeOp(node, simplified()->ObjectIsMinusZero());
525 return Changed(node);
526 }
else if (rhs_type.Is(Type::MinusZero())) {
528 node->RemoveInput(1);
529 NodeProperties::ChangeOp(node, simplified()->ObjectIsMinusZero());
530 return Changed(node);
531 }
else if (lhs_type.Is(Type::NaN())) {
533 node->RemoveInput(0);
534 NodeProperties::ChangeOp(node, simplified()->ObjectIsNaN());
535 return Changed(node);
536 }
else if (rhs_type.Is(Type::NaN())) {
538 node->RemoveInput(1);
539 NodeProperties::ChangeOp(node, simplified()->ObjectIsNaN());
540 return Changed(node);
541 }
else if (lhs_type.Is(Type::PlainNumber()) &&
542 rhs_type.Is(Type::PlainNumber())) {
544 NodeProperties::ChangeOp(node, simplified()->NumberEqual());
545 return Changed(node);
550 Reduction TypedOptimization::ReduceSelect(Node* node) {
551 DCHECK_EQ(IrOpcode::kSelect, node->opcode());
552 Node*
const condition = NodeProperties::GetValueInput(node, 0);
553 Type const condition_type = NodeProperties::GetType(condition);
554 Node*
const vtrue = NodeProperties::GetValueInput(node, 1);
555 Type const vtrue_type = NodeProperties::GetType(vtrue);
556 Node*
const vfalse = NodeProperties::GetValueInput(node, 2);
557 Type const vfalse_type = NodeProperties::GetType(vfalse);
558 if (condition_type.Is(true_type_)) {
560 return Replace(vtrue);
562 if (condition_type.Is(false_type_)) {
564 return Replace(vfalse);
566 if (vtrue_type.Is(true_type_) && vfalse_type.Is(false_type_)) {
568 return Replace(condition);
570 if (vtrue_type.Is(false_type_) && vfalse_type.Is(true_type_)) {
572 node->TrimInputCount(1);
573 NodeProperties::ChangeOp(node, simplified()->BooleanNot());
574 return Changed(node);
578 Type type = Type::Union(vtrue_type, vfalse_type, graph()->zone());
579 Type const node_type = NodeProperties::GetType(node);
580 if (!node_type.Is(type)) {
581 type = Type::Intersect(node_type, type, graph()->zone());
582 NodeProperties::SetType(node, type);
583 return Changed(node);
588 Reduction TypedOptimization::ReduceSpeculativeToNumber(Node* node) {
589 DCHECK_EQ(IrOpcode::kSpeculativeToNumber, node->opcode());
590 Node*
const input = NodeProperties::GetValueInput(node, 0);
591 Type const input_type = NodeProperties::GetType(input);
592 if (input_type.Is(Type::Number())) {
594 ReplaceWithValue(node, input);
595 return Replace(input);
600 Reduction TypedOptimization::ReduceTypeOf(Node* node) {
601 Node*
const input = node->InputAt(0);
602 Type const type = NodeProperties::GetType(input);
603 Factory*
const f = factory();
604 if (type.Is(Type::Boolean())) {
606 jsgraph()->Constant(ObjectRef(broker(), f->boolean_string())));
607 }
else if (type.Is(Type::Number())) {
609 jsgraph()->Constant(ObjectRef(broker(), f->number_string())));
610 }
else if (type.Is(Type::String())) {
612 jsgraph()->Constant(ObjectRef(broker(), f->string_string())));
613 }
else if (type.Is(Type::BigInt())) {
615 jsgraph()->Constant(ObjectRef(broker(), f->bigint_string())));
616 }
else if (type.Is(Type::Symbol())) {
618 jsgraph()->Constant(ObjectRef(broker(), f->symbol_string())));
619 }
else if (type.Is(Type::OtherUndetectableOrUndefined())) {
621 jsgraph()->Constant(ObjectRef(broker(), f->undefined_string())));
622 }
else if (type.Is(Type::NonCallableOrNull())) {
624 jsgraph()->Constant(ObjectRef(broker(), f->object_string())));
625 }
else if (type.Is(Type::Function())) {
627 jsgraph()->Constant(ObjectRef(broker(), f->function_string())));
632 Reduction TypedOptimization::ReduceToBoolean(Node* node) {
633 Node*
const input = node->InputAt(0);
634 Type const input_type = NodeProperties::GetType(input);
635 if (input_type.Is(Type::Boolean())) {
637 return Replace(input);
638 }
else if (input_type.Is(Type::OrderedNumber())) {
640 node->ReplaceInput(0, graph()->NewNode(simplified()->NumberEqual(), input,
641 jsgraph()->ZeroConstant()));
642 node->TrimInputCount(1);
643 NodeProperties::ChangeOp(node, simplified()->BooleanNot());
644 return Changed(node);
645 }
else if (input_type.Is(Type::Number())) {
647 node->TrimInputCount(1);
648 NodeProperties::ChangeOp(node, simplified()->NumberToBoolean());
649 return Changed(node);
650 }
else if (input_type.Is(Type::DetectableReceiverOrNull())) {
653 node->ReplaceInput(0, graph()->NewNode(simplified()->ReferenceEqual(),
654 input, jsgraph()->NullConstant()));
655 node->TrimInputCount(1);
656 NodeProperties::ChangeOp(node, simplified()->BooleanNot());
657 return Changed(node);
658 }
else if (input_type.Is(Type::ReceiverOrNullOrUndefined())) {
662 0, graph()->NewNode(simplified()->ObjectIsUndetectable(), input));
663 node->TrimInputCount(1);
664 NodeProperties::ChangeOp(node, simplified()->BooleanNot());
665 return Changed(node);
666 }
else if (input_type.Is(Type::String())) {
668 node->ReplaceInput(0,
669 graph()->NewNode(simplified()->ReferenceEqual(), input,
670 jsgraph()->EmptyStringConstant()));
671 node->TrimInputCount(1);
672 NodeProperties::ChangeOp(node, simplified()->BooleanNot());
673 return Changed(node);
679 bool BothAre(
Type t1,
Type t2,
Type t3) {
return t1.Is(t3) && t2.Is(t3); }
682 return !t1.Maybe(t3) && !t2.Maybe(t3);
685 const Operator* NumberOpFromSpeculativeNumberOp(
686 SimplifiedOperatorBuilder* simplified,
const Operator* op) {
687 switch (op->opcode()) {
688 case IrOpcode::kSpeculativeNumberEqual:
689 return simplified->NumberEqual();
690 case IrOpcode::kSpeculativeNumberLessThan:
691 return simplified->NumberLessThan();
692 case IrOpcode::kSpeculativeNumberLessThanOrEqual:
693 return simplified->NumberLessThanOrEqual();
694 case IrOpcode::kSpeculativeNumberAdd:
697 case IrOpcode::kSpeculativeNumberSubtract:
698 return simplified->NumberSubtract();
699 case IrOpcode::kSpeculativeNumberMultiply:
700 return simplified->NumberMultiply();
701 case IrOpcode::kSpeculativeNumberDivide:
702 return simplified->NumberDivide();
703 case IrOpcode::kSpeculativeNumberModulus:
704 return simplified->NumberModulus();
713 Reduction TypedOptimization::ReduceSpeculativeNumberAdd(Node* node) {
714 Node*
const lhs = NodeProperties::GetValueInput(node, 0);
715 Node*
const rhs = NodeProperties::GetValueInput(node, 1);
716 Type const lhs_type = NodeProperties::GetType(lhs);
717 Type const rhs_type = NodeProperties::GetType(rhs);
718 NumberOperationHint hint = NumberOperationHintOf(node->op());
719 if ((hint == NumberOperationHint::kNumber ||
720 hint == NumberOperationHint::kNumberOrOddball) &&
721 BothAre(lhs_type, rhs_type, Type::PlainPrimitive()) &&
722 NeitherCanBe(lhs_type, rhs_type, Type::StringOrReceiver())) {
725 Node*
const toNum_lhs =
726 graph()->NewNode(simplified()->PlainPrimitiveToNumber(), lhs);
727 Node*
const toNum_rhs =
728 graph()->NewNode(simplified()->PlainPrimitiveToNumber(), rhs);
730 graph()->NewNode(simplified()->NumberAdd(), toNum_lhs, toNum_rhs);
731 ReplaceWithValue(node, value);
732 return Replace(node);
737 Reduction TypedOptimization::ReduceJSToNumberInput(Node* input) {
739 Type input_type = NodeProperties::GetType(input);
741 if (input_type.Is(Type::String())) {
742 HeapObjectMatcher m(input);
743 if (m.HasValue() && m.Ref(broker()).IsString()) {
744 StringRef input_value = m.Ref(broker()).AsString();
746 ASSIGN_RETURN_NO_CHANGE_IF_DATA_MISSING(number, input_value.ToNumber());
747 return Replace(jsgraph()->Constant(number));
750 if (input_type.IsHeapConstant()) {
751 HeapObjectRef input_value = input_type.AsHeapConstant()->Ref();
752 if (input_value.map().oddball_type() != OddballType::kNone) {
753 return Replace(jsgraph()->Constant(input_value.OddballToNumber()));
756 if (input_type.Is(Type::Number())) {
758 return Changed(input);
760 if (input_type.Is(Type::Undefined())) {
762 return Replace(jsgraph()->NaNConstant());
764 if (input_type.Is(Type::Null())) {
766 return Replace(jsgraph()->ZeroConstant());
771 Node* TypedOptimization::ConvertPlainPrimitiveToNumber(Node* node) {
772 DCHECK(NodeProperties::GetType(node).Is(Type::PlainPrimitive()));
774 Reduction
const reduction = ReduceJSToNumberInput(node);
775 if (reduction.Changed())
return reduction.replacement();
776 if (NodeProperties::GetType(node).Is(Type::Number())) {
779 return graph()->NewNode(simplified()->PlainPrimitiveToNumber(), node);
782 Reduction TypedOptimization::ReduceSpeculativeNumberBinop(Node* node) {
783 Node*
const lhs = NodeProperties::GetValueInput(node, 0);
784 Node*
const rhs = NodeProperties::GetValueInput(node, 1);
785 Type const lhs_type = NodeProperties::GetType(lhs);
786 Type const rhs_type = NodeProperties::GetType(rhs);
787 NumberOperationHint hint = NumberOperationHintOf(node->op());
788 if ((hint == NumberOperationHint::kNumber ||
789 hint == NumberOperationHint::kNumberOrOddball) &&
790 BothAre(lhs_type, rhs_type, Type::NumberOrUndefinedOrNullOrBoolean())) {
794 Node*
const toNum_lhs = ConvertPlainPrimitiveToNumber(lhs);
795 Node*
const toNum_rhs = ConvertPlainPrimitiveToNumber(rhs);
796 Node*
const value = graph()->NewNode(
797 NumberOpFromSpeculativeNumberOp(simplified(), node->op()), toNum_lhs,
799 ReplaceWithValue(node, value);
800 return Replace(node);
805 Reduction TypedOptimization::ReduceSpeculativeNumberComparison(Node* node) {
806 Node*
const lhs = NodeProperties::GetValueInput(node, 0);
807 Node*
const rhs = NodeProperties::GetValueInput(node, 1);
808 Type const lhs_type = NodeProperties::GetType(lhs);
809 Type const rhs_type = NodeProperties::GetType(rhs);
810 if (BothAre(lhs_type, rhs_type, Type::Signed32()) ||
811 BothAre(lhs_type, rhs_type, Type::Unsigned32())) {
812 Node*
const value = graph()->NewNode(
813 NumberOpFromSpeculativeNumberOp(simplified(), node->op()), lhs, rhs);
814 ReplaceWithValue(node, value);
815 return Replace(node);
820 Factory* TypedOptimization::factory()
const {
821 return jsgraph()->isolate()->factory();
824 Graph* TypedOptimization::graph()
const {
return jsgraph()->graph(); }
826 SimplifiedOperatorBuilder* TypedOptimization::simplified()
const {
827 return jsgraph()->simplified();