Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(175)

Side by Side Diff: src/compiler/js-typed-lowering.cc

Issue 792463003: [turbofan] Turn JSToBoolean and JSUnaryNot into pure operators. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Created 6 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2014 the V8 project authors. All rights reserved. 1 // Copyright 2014 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "src/compiler/access-builder.h" 5 #include "src/compiler/access-builder.h"
6 #include "src/compiler/graph-inl.h" 6 #include "src/compiler/graph-inl.h"
7 #include "src/compiler/js-builtin-reducer.h" 7 #include "src/compiler/js-builtin-reducer.h"
8 #include "src/compiler/js-typed-lowering.h" 8 #include "src/compiler/js-typed-lowering.h"
9 #include "src/compiler/node-aux-data-inl.h" 9 #include "src/compiler/node-aux-data-inl.h"
10 #include "src/compiler/node-matchers.h" 10 #include "src/compiler/node-matchers.h"
(...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after
134 // that encapsulates changing the operator and re-typing. 134 // that encapsulates changing the operator and re-typing.
135 Bounds const bounds = NodeProperties::GetBounds(node_); 135 Bounds const bounds = NodeProperties::GetBounds(node_);
136 NodeProperties::SetBounds(node_, Bounds::NarrowUpper(bounds, type, zone())); 136 NodeProperties::SetBounds(node_, Bounds::NarrowUpper(bounds, type, zone()));
137 137
138 if (invert) { 138 if (invert) {
139 // Insert an boolean not to invert the value. 139 // Insert an boolean not to invert the value.
140 Node* value = graph()->NewNode(simplified()->BooleanNot(), node_); 140 Node* value = graph()->NewNode(simplified()->BooleanNot(), node_);
141 node_->ReplaceUses(value); 141 node_->ReplaceUses(value);
142 // Note: ReplaceUses() smashes all uses, so smash it back here. 142 // Note: ReplaceUses() smashes all uses, so smash it back here.
143 value->ReplaceInput(0, node_); 143 value->ReplaceInput(0, node_);
144 return lowering_->ReplaceWith(value); 144 return lowering_->Replace(value);
145 } 145 }
146 return lowering_->Changed(node_); 146 return lowering_->Changed(node_);
147 } 147 }
148 148
149 Reduction ChangeToPureOperator(const Operator* op, Type* type) { 149 Reduction ChangeToPureOperator(const Operator* op, Type* type) {
150 return ChangeToPureOperator(op, false, type); 150 return ChangeToPureOperator(op, false, type);
151 } 151 }
152 152
153 bool OneInputIs(Type* t) { return left_type_->Is(t) || right_type_->Is(t); } 153 bool OneInputIs(Type* t) { return left_type_->Is(t) || right_type_->Is(t); }
154 154
(...skipping 342 matching lines...) Expand 10 before | Expand all | Expand 10 after
497 if (result.Changed()) return result; 497 if (result.Changed()) return result;
498 return Changed(input); // JSToNumber(JSToNumber(x)) => JSToNumber(x) 498 return Changed(input); // JSToNumber(JSToNumber(x)) => JSToNumber(x)
499 } 499 }
500 Type* input_type = NodeProperties::GetBounds(input).upper; 500 Type* input_type = NodeProperties::GetBounds(input).upper;
501 if (input_type->Is(Type::Number())) { 501 if (input_type->Is(Type::Number())) {
502 // JSToNumber(x:number) => x 502 // JSToNumber(x:number) => x
503 return Changed(input); 503 return Changed(input);
504 } 504 }
505 if (input_type->Is(Type::Undefined())) { 505 if (input_type->Is(Type::Undefined())) {
506 // JSToNumber(undefined) => #NaN 506 // JSToNumber(undefined) => #NaN
507 return ReplaceWith(jsgraph()->NaNConstant()); 507 return Replace(jsgraph()->NaNConstant());
508 } 508 }
509 if (input_type->Is(Type::Null())) { 509 if (input_type->Is(Type::Null())) {
510 // JSToNumber(null) => #0 510 // JSToNumber(null) => #0
511 return ReplaceWith(jsgraph()->ZeroConstant()); 511 return Replace(jsgraph()->ZeroConstant());
512 } 512 }
513 if (input_type->Is(Type::Boolean())) { 513 if (input_type->Is(Type::Boolean())) {
514 // JSToNumber(x:boolean) => BooleanToNumber(x) 514 // JSToNumber(x:boolean) => BooleanToNumber(x)
515 return ReplaceWith( 515 return Replace(graph()->NewNode(simplified()->BooleanToNumber(), input));
516 graph()->NewNode(simplified()->BooleanToNumber(), input));
517 } 516 }
518 // TODO(turbofan): js-typed-lowering of ToNumber(x:string) 517 // TODO(turbofan): js-typed-lowering of ToNumber(x:string)
519 return NoChange(); 518 return NoChange();
520 } 519 }
521 520
522 521
523 Reduction JSTypedLowering::ReduceJSToNumber(Node* node) { 522 Reduction JSTypedLowering::ReduceJSToNumber(Node* node) {
524 // Try to reduce the input first. 523 // Try to reduce the input first.
525 Node* const input = node->InputAt(0); 524 Node* const input = node->InputAt(0);
526 Reduction reduction = ReduceJSToNumberInput(input); 525 Reduction reduction = ReduceJSToNumberInput(input);
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
577 RelaxEffects(input); 576 RelaxEffects(input);
578 return result; 577 return result;
579 } 578 }
580 return Changed(input); // JSToString(JSToString(x)) => JSToString(x) 579 return Changed(input); // JSToString(JSToString(x)) => JSToString(x)
581 } 580 }
582 Type* input_type = NodeProperties::GetBounds(input).upper; 581 Type* input_type = NodeProperties::GetBounds(input).upper;
583 if (input_type->Is(Type::String())) { 582 if (input_type->Is(Type::String())) {
584 return Changed(input); // JSToString(x:string) => x 583 return Changed(input); // JSToString(x:string) => x
585 } 584 }
586 if (input_type->Is(Type::Undefined())) { 585 if (input_type->Is(Type::Undefined())) {
587 return ReplaceWith(jsgraph()->HeapConstant( 586 return Replace(jsgraph()->HeapConstant(
588 graph()->zone()->isolate()->factory()->undefined_string())); 587 graph()->zone()->isolate()->factory()->undefined_string()));
589 } 588 }
590 if (input_type->Is(Type::Null())) { 589 if (input_type->Is(Type::Null())) {
591 return ReplaceWith(jsgraph()->HeapConstant( 590 return Replace(jsgraph()->HeapConstant(
592 graph()->zone()->isolate()->factory()->null_string())); 591 graph()->zone()->isolate()->factory()->null_string()));
593 } 592 }
594 // TODO(turbofan): js-typed-lowering of ToString(x:boolean) 593 // TODO(turbofan): js-typed-lowering of ToString(x:boolean)
595 // TODO(turbofan): js-typed-lowering of ToString(x:number) 594 // TODO(turbofan): js-typed-lowering of ToString(x:number)
596 return NoChange(); 595 return NoChange();
597 } 596 }
598 597
599 598
600 Reduction JSTypedLowering::ReduceJSToBooleanInput(Node* input) { 599 Reduction JSTypedLowering::ReduceJSToBooleanInput(Node* input) {
601 if (input->opcode() == IrOpcode::kJSToBoolean) { 600 if (input->opcode() == IrOpcode::kJSToBoolean) {
602 // Recursively try to reduce the input first. 601 // Recursively try to reduce the input first.
603 Reduction result = ReduceJSToBoolean(input); 602 Reduction result = ReduceJSToBoolean(input);
604 if (result.Changed()) return result; 603 if (result.Changed()) return result;
605 return Changed(input); // JSToBoolean(JSToBoolean(x)) => JSToBoolean(x) 604 return Changed(input); // JSToBoolean(JSToBoolean(x)) => JSToBoolean(x)
606 } 605 }
607 Type* input_type = NodeProperties::GetBounds(input).upper; 606 Type* input_type = NodeProperties::GetBounds(input).upper;
608 if (input_type->Is(Type::Boolean())) { 607 if (input_type->Is(Type::Boolean())) {
609 return Changed(input); // JSToBoolean(x:boolean) => x 608 return Changed(input); // JSToBoolean(x:boolean) => x
610 } 609 }
611 if (input_type->Is(Type::Undefined())) { 610 if (input_type->Is(Type::Undefined())) {
612 // JSToBoolean(undefined) => #false 611 // JSToBoolean(undefined) => #false
613 return ReplaceWith(jsgraph()->FalseConstant()); 612 return Replace(jsgraph()->FalseConstant());
614 } 613 }
615 if (input_type->Is(Type::Null())) { 614 if (input_type->Is(Type::Null())) {
616 // JSToBoolean(null) => #false 615 // JSToBoolean(null) => #false
617 return ReplaceWith(jsgraph()->FalseConstant()); 616 return Replace(jsgraph()->FalseConstant());
618 } 617 }
619 if (input_type->Is(Type::DetectableReceiver())) { 618 if (input_type->Is(Type::DetectableReceiver())) {
620 // JSToBoolean(x:detectable) => #true 619 // JSToBoolean(x:detectable) => #true
621 return ReplaceWith(jsgraph()->TrueConstant()); 620 return Replace(jsgraph()->TrueConstant());
622 } 621 }
623 if (input_type->Is(Type::Undetectable())) { 622 if (input_type->Is(Type::Undetectable())) {
624 // JSToBoolean(x:undetectable) => #false 623 // JSToBoolean(x:undetectable) => #false
625 return ReplaceWith(jsgraph()->FalseConstant()); 624 return Replace(jsgraph()->FalseConstant());
626 } 625 }
627 if (input_type->Is(Type::OrderedNumber())) { 626 if (input_type->Is(Type::OrderedNumber())) {
628 // JSToBoolean(x:ordered-number) => BooleanNot(NumberEqual(x, #0)) 627 // JSToBoolean(x:ordered-number) => BooleanNot(NumberEqual(x, #0))
629 Node* cmp = graph()->NewNode(simplified()->NumberEqual(), input, 628 Node* cmp = graph()->NewNode(simplified()->NumberEqual(), input,
630 jsgraph()->ZeroConstant()); 629 jsgraph()->ZeroConstant());
631 Node* inv = graph()->NewNode(simplified()->BooleanNot(), cmp); 630 Node* inv = graph()->NewNode(simplified()->BooleanNot(), cmp);
632 return ReplaceWith(inv); 631 return Replace(inv);
633 } 632 }
634 if (input_type->Is(Type::String())) { 633 if (input_type->Is(Type::String())) {
635 // JSToBoolean(x:string) => BooleanNot(NumberEqual(x.length, #0)) 634 // JSToBoolean(x:string) => BooleanNot(NumberEqual(x.length, #0))
636 FieldAccess access = AccessBuilder::ForStringLength(); 635 FieldAccess access = AccessBuilder::ForStringLength();
637 Node* length = graph()->NewNode(simplified()->LoadField(access), input, 636 Node* length = graph()->NewNode(simplified()->LoadField(access), input,
638 graph()->start(), graph()->start()); 637 graph()->start(), graph()->start());
639 Node* cmp = graph()->NewNode(simplified()->NumberEqual(), length, 638 Node* cmp = graph()->NewNode(simplified()->NumberEqual(), length,
640 jsgraph()->ZeroConstant()); 639 jsgraph()->ZeroConstant());
641 Node* inv = graph()->NewNode(simplified()->BooleanNot(), cmp); 640 Node* inv = graph()->NewNode(simplified()->BooleanNot(), cmp);
642 return ReplaceWith(inv); 641 return Replace(inv);
643 } 642 }
644 return NoChange(); 643 return NoChange();
645 } 644 }
646 645
647 646
648 Reduction JSTypedLowering::ReduceJSToBoolean(Node* node) { 647 Reduction JSTypedLowering::ReduceJSToBoolean(Node* node) {
649 // Try to reduce the input first. 648 // Try to reduce the input first.
650 Node* const input = node->InputAt(0); 649 Node* const input = node->InputAt(0);
651 Reduction reduction = ReduceJSToBooleanInput(input); 650 Reduction reduction = ReduceJSToBooleanInput(input);
652 if (reduction.Changed()) { 651 if (reduction.Changed()) return reduction;
653 NodeProperties::ReplaceWithValue(node, reduction.replacement()); 652 if (input->opcode() == IrOpcode::kPhi) {
654 return reduction; 653 // JSToBoolean(phi(x1,...,xn,control),context)
655 } 654 // => phi(JSToBoolean(x1,no-context),...,JSToBoolean(xn,no-context))
656 Type* const input_type = NodeProperties::GetBounds(input).upper;
657 if (input->opcode() == IrOpcode::kPhi && input_type->Is(Type::Primitive())) {
658 Node* const context = node->InputAt(1);
659 // JSToBoolean(phi(x1,...,xn,control):primitive)
660 // => phi(JSToBoolean(x1),...,JSToBoolean(xn),control):boolean
661 RelaxEffects(node);
662 int const input_count = input->InputCount() - 1; 655 int const input_count = input->InputCount() - 1;
663 Node* const control = input->InputAt(input_count); 656 Node* const control = input->InputAt(input_count);
664 DCHECK_LE(0, input_count); 657 DCHECK_LE(0, input_count);
665 DCHECK(NodeProperties::IsControl(control)); 658 DCHECK(NodeProperties::IsControl(control));
666 DCHECK(NodeProperties::GetBounds(node).upper->Is(Type::Boolean())); 659 DCHECK(NodeProperties::GetBounds(node).upper->Is(Type::Boolean()));
667 DCHECK(!NodeProperties::GetBounds(input).upper->Is(Type::Boolean())); 660 DCHECK(!NodeProperties::GetBounds(input).upper->Is(Type::Boolean()));
668 node->set_op(common()->Phi(kMachAnyTagged, input_count)); 661 node->set_op(common()->Phi(kMachAnyTagged, input_count));
669 for (int i = 0; i < input_count; ++i) { 662 for (int i = 0; i < input_count; ++i) {
670 Node* value = input->InputAt(i); 663 Node* value = input->InputAt(i);
671 // Recursively try to reduce the value first. 664 // Recursively try to reduce the value first.
672 Reduction reduction = ReduceJSToBooleanInput(value); 665 Reduction reduction = ReduceJSToBooleanInput(value);
673 if (reduction.Changed()) { 666 if (reduction.Changed()) {
674 value = reduction.replacement(); 667 value = reduction.replacement();
675 } else { 668 } else {
676 value = graph()->NewNode(javascript()->ToBoolean(), value, context, 669 // We must be very careful not to introduce cycles when pushing
677 graph()->start(), graph()->start()); 670 // operations into phis. It is safe for {value}, since it appears
671 // as input to the phi that we are replacing, but it's not safe
672 // to simply reuse the context of the {node}. However, ToBoolean()
673 // does not require a context anyways, so it's safe to discard it
674 // here and pass the dummy context.
675 value = graph()->NewNode(javascript()->ToBoolean(), value,
676 jsgraph()->NoContextConstant());
678 } 677 }
679 if (i < node->InputCount()) { 678 if (i < node->InputCount()) {
680 node->ReplaceInput(i, value); 679 node->ReplaceInput(i, value);
681 } else { 680 } else {
682 node->AppendInput(graph()->zone(), value); 681 node->AppendInput(graph()->zone(), value);
683 } 682 }
684 } 683 }
685 if (input_count < node->InputCount()) { 684 if (input_count < node->InputCount()) {
686 node->ReplaceInput(input_count, control); 685 node->ReplaceInput(input_count, control);
687 } else { 686 } else {
688 node->AppendInput(graph()->zone(), control); 687 node->AppendInput(graph()->zone(), control);
689 } 688 }
690 node->TrimInputCount(input_count + 1); 689 node->TrimInputCount(input_count + 1);
691 return Changed(node); 690 return Changed(node);
692 } 691 }
692 if (input->opcode() == IrOpcode::kSelect) {
693 // JSToBoolean(select(c,x1,x2),context)
694 // => select(c,JSToBoolean(x1,no-context),...,JSToBoolean(x2,no-context))
695 int const input_count = input->InputCount();
696 BranchHint const input_hint = SelectParametersOf(input->op()).hint();
697 DCHECK_EQ(3, input_count);
698 DCHECK(NodeProperties::GetBounds(node).upper->Is(Type::Boolean()));
699 DCHECK(!NodeProperties::GetBounds(input).upper->Is(Type::Boolean()));
700 node->set_op(common()->Select(kMachAnyTagged, input_hint));
701 node->InsertInput(graph()->zone(), 0, input->InputAt(0));
702 for (int i = 1; i < input_count; ++i) {
703 Node* value = input->InputAt(i);
704 // Recursively try to reduce the value first.
705 Reduction reduction = ReduceJSToBooleanInput(value);
706 if (reduction.Changed()) {
707 value = reduction.replacement();
708 } else {
709 // We must be very careful not to introduce cycles when pushing
710 // operations into selects. It is safe for {value}, since it appears
711 // as input to the select that we are replacing, but it's not safe
712 // to simply reuse the context of the {node}. However, ToBoolean()
713 // does not require a context anyways, so it's safe to discard it
714 // here and pass the dummy context.
715 value = graph()->NewNode(javascript()->ToBoolean(), value,
716 jsgraph()->NoContextConstant());
717 }
718 node->ReplaceInput(i, value);
719 }
720 DCHECK_EQ(3, node->InputCount());
721 return Changed(node);
722 }
693 return NoChange(); 723 return NoChange();
694 } 724 }
695 725
696 726
697 Reduction JSTypedLowering::ReduceJSLoadProperty(Node* node) { 727 Reduction JSTypedLowering::ReduceJSLoadProperty(Node* node) {
698 Node* key = NodeProperties::GetValueInput(node, 1); 728 Node* key = NodeProperties::GetValueInput(node, 1);
699 Node* base = NodeProperties::GetValueInput(node, 0); 729 Node* base = NodeProperties::GetValueInput(node, 0);
700 Type* key_type = NodeProperties::GetBounds(key).upper; 730 Type* key_type = NodeProperties::GetBounds(key).upper;
701 Type* base_type = NodeProperties::GetBounds(base).upper; 731 Type* base_type = NodeProperties::GetBounds(base).upper;
702 // TODO(mstarzinger): This lowering is not correct if: 732 // TODO(mstarzinger): This lowering is not correct if:
(...skipping 205 matching lines...) Expand 10 before | Expand all | Expand 10 after
908 case IrOpcode::kJSSubtract: 938 case IrOpcode::kJSSubtract:
909 return ReduceNumberBinop(node, simplified()->NumberSubtract()); 939 return ReduceNumberBinop(node, simplified()->NumberSubtract());
910 case IrOpcode::kJSMultiply: 940 case IrOpcode::kJSMultiply:
911 return ReduceJSMultiply(node); 941 return ReduceJSMultiply(node);
912 case IrOpcode::kJSDivide: 942 case IrOpcode::kJSDivide:
913 return ReduceNumberBinop(node, simplified()->NumberDivide()); 943 return ReduceNumberBinop(node, simplified()->NumberDivide());
914 case IrOpcode::kJSModulus: 944 case IrOpcode::kJSModulus:
915 return ReduceNumberBinop(node, simplified()->NumberModulus()); 945 return ReduceNumberBinop(node, simplified()->NumberModulus());
916 case IrOpcode::kJSUnaryNot: { 946 case IrOpcode::kJSUnaryNot: {
917 Reduction result = ReduceJSToBooleanInput(node->InputAt(0)); 947 Reduction result = ReduceJSToBooleanInput(node->InputAt(0));
918 Node* value;
919 if (result.Changed()) { 948 if (result.Changed()) {
920 // JSUnaryNot(x:boolean) => BooleanNot(x) 949 // JSUnaryNot(x:boolean) => BooleanNot(x)
921 value = 950 node = result.replacement();
922 graph()->NewNode(simplified()->BooleanNot(), result.replacement());
923 NodeProperties::ReplaceWithValue(node, value);
924 return Changed(value);
925 } else { 951 } else {
926 // JSUnaryNot(x) => BooleanNot(JSToBoolean(x)) 952 // JSUnaryNot(x) => BooleanNot(JSToBoolean(x))
927 value = graph()->NewNode(simplified()->BooleanNot(), node);
928 node->set_op(javascript()->ToBoolean()); 953 node->set_op(javascript()->ToBoolean());
929 NodeProperties::ReplaceWithValue(node, value, node);
930 // Note: ReplaceUses() smashes all uses, so smash it back here.
931 value->ReplaceInput(0, node);
932 return Changed(node);
933 } 954 }
955 Node* value = graph()->NewNode(simplified()->BooleanNot(), node);
956 return Replace(value);
934 } 957 }
935 case IrOpcode::kJSToBoolean: 958 case IrOpcode::kJSToBoolean:
936 return ReduceJSToBoolean(node); 959 return ReduceJSToBoolean(node);
937 case IrOpcode::kJSToNumber: 960 case IrOpcode::kJSToNumber:
938 return ReduceJSToNumber(node); 961 return ReduceJSToNumber(node);
939 case IrOpcode::kJSToString: 962 case IrOpcode::kJSToString:
940 return ReplaceWithReduction(node, 963 return ReplaceWithReduction(node,
941 ReduceJSToStringInput(node->InputAt(0))); 964 ReduceJSToStringInput(node->InputAt(0)));
942 case IrOpcode::kJSLoadProperty: 965 case IrOpcode::kJSLoadProperty:
943 return ReduceJSLoadProperty(node); 966 return ReduceJSLoadProperty(node);
(...skipping 14 matching lines...) Expand all
958 981
959 Node* JSTypedLowering::Word32Shl(Node* const lhs, int32_t const rhs) { 982 Node* JSTypedLowering::Word32Shl(Node* const lhs, int32_t const rhs) {
960 if (rhs == 0) return lhs; 983 if (rhs == 0) return lhs;
961 return graph()->NewNode(machine()->Word32Shl(), lhs, 984 return graph()->NewNode(machine()->Word32Shl(), lhs,
962 jsgraph()->Int32Constant(rhs)); 985 jsgraph()->Int32Constant(rhs));
963 } 986 }
964 987
965 } // namespace compiler 988 } // namespace compiler
966 } // namespace internal 989 } // namespace internal
967 } // namespace v8 990 } // namespace v8
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698