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

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

Issue 800833003: [turbofan] Correctify JSToBoolean lowering. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Improve simplified lowering. Created 5 years, 11 months 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
« no previous file with comments | « src/compiler/js-typed-lowering.h ('k') | src/compiler/opcodes.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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-graph.h" 7 #include "src/compiler/js-graph.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 472 matching lines...) Expand 10 before | Expand all | Expand 10 after
483 return r.ChangeToPureOperator(simplified()->StringEqual(), invert); 483 return r.ChangeToPureOperator(simplified()->StringEqual(), invert);
484 } 484 }
485 if (r.BothInputsAre(Type::Number())) { 485 if (r.BothInputsAre(Type::Number())) {
486 return r.ChangeToPureOperator(simplified()->NumberEqual(), invert); 486 return r.ChangeToPureOperator(simplified()->NumberEqual(), invert);
487 } 487 }
488 // TODO(turbofan): js-typed-lowering of StrictEqual(mixed types) 488 // TODO(turbofan): js-typed-lowering of StrictEqual(mixed types)
489 return NoChange(); 489 return NoChange();
490 } 490 }
491 491
492 492
493 Reduction JSTypedLowering::ReduceJSToBooleanInput(Node* input) { 493 Reduction JSTypedLowering::ReduceJSUnaryNot(Node* node) {
494 if (input->opcode() == IrOpcode::kJSToBoolean) { 494 Node* input = node->InputAt(0);
495 // Recursively try to reduce the input first.
496 Reduction result = ReduceJSToBoolean(input);
497 if (result.Changed()) return result;
498 return Changed(input); // JSToBoolean(JSToBoolean(x)) => JSToBoolean(x)
499 }
500 // Check if we have a cached conversion.
501 Node* conversion = FindConversion<IrOpcode::kJSToBoolean>(input);
502 if (conversion) return Replace(conversion);
503 Type* input_type = NodeProperties::GetBounds(input).upper; 495 Type* input_type = NodeProperties::GetBounds(input).upper;
504 if (input_type->Is(Type::Boolean())) { 496 if (input_type->Is(Type::Boolean())) {
505 return Changed(input); // JSToBoolean(x:boolean) => x 497 // JSUnaryNot(x:boolean,context) => BooleanNot(x)
498 node->set_op(simplified()->BooleanNot());
499 node->TrimInputCount(1);
500 return Changed(node);
506 } 501 }
507 if (input_type->Is(Type::Undefined())) { 502 // JSUnaryNot(x,context) => BooleanNot(AnyToBoolean(x))
508 // JSToBoolean(undefined) => #false 503 node->set_op(simplified()->BooleanNot());
509 return Replace(jsgraph()->FalseConstant()); 504 node->ReplaceInput(0, graph()->NewNode(simplified()->AnyToBoolean(), input));
510 } 505 node->TrimInputCount(1);
511 if (input_type->Is(Type::Null())) { 506 return Changed(node);
512 // JSToBoolean(null) => #false
513 return Replace(jsgraph()->FalseConstant());
514 }
515 if (input_type->Is(Type::DetectableReceiver())) {
516 // JSToBoolean(x:detectable) => #true
517 return Replace(jsgraph()->TrueConstant());
518 }
519 if (input_type->Is(Type::Undetectable())) {
520 // JSToBoolean(x:undetectable) => #false
521 return Replace(jsgraph()->FalseConstant());
522 }
523 if (input_type->Is(Type::OrderedNumber())) {
524 // JSToBoolean(x:ordered-number) => BooleanNot(NumberEqual(x, #0))
525 Node* cmp = graph()->NewNode(simplified()->NumberEqual(), input,
526 jsgraph()->ZeroConstant());
527 Node* inv = graph()->NewNode(simplified()->BooleanNot(), cmp);
528 return Replace(inv);
529 }
530 if (input_type->Is(Type::String())) {
531 // JSToBoolean(x:string) => BooleanNot(NumberEqual(x.length, #0))
532 FieldAccess access = AccessBuilder::ForStringLength();
533 Node* length = graph()->NewNode(simplified()->LoadField(access), input,
534 graph()->start(), graph()->start());
535 Node* cmp = graph()->NewNode(simplified()->NumberEqual(), length,
536 jsgraph()->ZeroConstant());
537 Node* inv = graph()->NewNode(simplified()->BooleanNot(), cmp);
538 return Replace(inv);
539 }
540 return NoChange();
541 } 507 }
542 508
543 509
544 Reduction JSTypedLowering::ReduceJSToBoolean(Node* node) { 510 Reduction JSTypedLowering::ReduceJSToBoolean(Node* node) {
545 // Try to reduce the input first. 511 Node* input = node->InputAt(0);
546 Node* const input = node->InputAt(0); 512 Type* input_type = NodeProperties::GetBounds(input).upper;
547 Reduction reduction = ReduceJSToBooleanInput(input); 513 if (input_type->Is(Type::Boolean())) {
548 if (reduction.Changed()) return reduction; 514 // JSToBoolean(x:boolean,context) => x
549 if (input->opcode() == IrOpcode::kPhi) { 515 return Replace(input);
550 // JSToBoolean(phi(x1,...,xn,control),context)
551 // => phi(JSToBoolean(x1,no-context),...,JSToBoolean(xn,no-context))
552 int const input_count = input->InputCount() - 1;
553 Node* const control = input->InputAt(input_count);
554 DCHECK_LE(0, input_count);
555 DCHECK(NodeProperties::IsControl(control));
556 DCHECK(NodeProperties::GetBounds(node).upper->Is(Type::Boolean()));
557 DCHECK(!NodeProperties::GetBounds(input).upper->Is(Type::Boolean()));
558 node->set_op(common()->Phi(kMachAnyTagged, input_count));
559 for (int i = 0; i < input_count; ++i) {
560 // We must be very careful not to introduce cycles when pushing
561 // operations into phis. It is safe for {value}, since it appears
562 // as input to the phi that we are replacing, but it's not safe
563 // to simply reuse the context of the {node}. However, ToBoolean()
564 // does not require a context anyways, so it's safe to discard it
565 // here and pass the dummy context.
566 Node* const value = ConvertToBoolean(input->InputAt(i));
567 if (i < node->InputCount()) {
568 node->ReplaceInput(i, value);
569 } else {
570 node->AppendInput(graph()->zone(), value);
571 }
572 }
573 if (input_count < node->InputCount()) {
574 node->ReplaceInput(input_count, control);
575 } else {
576 node->AppendInput(graph()->zone(), control);
577 }
578 node->TrimInputCount(input_count + 1);
579 return Changed(node);
580 } 516 }
581 if (input->opcode() == IrOpcode::kSelect) { 517 // JSToBoolean(x,context) => AnyToBoolean(x)
582 // JSToBoolean(select(c,x1,x2),context) 518 node->set_op(simplified()->AnyToBoolean());
583 // => select(c,JSToBoolean(x1,no-context),...,JSToBoolean(x2,no-context)) 519 node->TrimInputCount(1);
584 int const input_count = input->InputCount(); 520 return Changed(node);
585 BranchHint const input_hint = SelectParametersOf(input->op()).hint();
586 DCHECK_EQ(3, input_count);
587 DCHECK(NodeProperties::GetBounds(node).upper->Is(Type::Boolean()));
588 DCHECK(!NodeProperties::GetBounds(input).upper->Is(Type::Boolean()));
589 node->set_op(common()->Select(kMachAnyTagged, input_hint));
590 node->InsertInput(graph()->zone(), 0, input->InputAt(0));
591 for (int i = 1; i < input_count; ++i) {
592 // We must be very careful not to introduce cycles when pushing
593 // operations into selects. It is safe for {value}, since it appears
594 // as input to the select that we are replacing, but it's not safe
595 // to simply reuse the context of the {node}. However, ToBoolean()
596 // does not require a context anyways, so it's safe to discard it
597 // here and pass the dummy context.
598 Node* const value = ConvertToBoolean(input->InputAt(i));
599 node->ReplaceInput(i, value);
600 }
601 DCHECK_EQ(3, node->InputCount());
602 return Changed(node);
603 }
604 InsertConversion(node);
605 if (node->InputAt(1) != jsgraph()->NoContextConstant()) {
606 // JSToBoolean(x,context) => JSToBoolean(x,no-context)
607 node->ReplaceInput(1, jsgraph()->NoContextConstant());
608 return Changed(node);
609 }
610 return NoChange();
611 } 521 }
612 522
613 523
614 Reduction JSTypedLowering::ReduceJSToNumberInput(Node* input) { 524 Reduction JSTypedLowering::ReduceJSToNumberInput(Node* input) {
615 if (input->opcode() == IrOpcode::kJSToNumber) { 525 if (input->opcode() == IrOpcode::kJSToNumber) {
616 // Recursively try to reduce the input first. 526 // Recursively try to reduce the input first.
617 Reduction result = ReduceJSToNumber(input); 527 Reduction result = ReduceJSToNumber(input);
618 if (result.Changed()) return result; 528 if (result.Changed()) return result;
619 return Changed(input); // JSToNumber(JSToNumber(x)) => JSToNumber(x) 529 return Changed(input); // JSToNumber(JSToNumber(x)) => JSToNumber(x)
620 } 530 }
(...skipping 344 matching lines...) Expand 10 before | Expand all | Expand 10 after
965 case IrOpcode::kJSAdd: 875 case IrOpcode::kJSAdd:
966 return ReduceJSAdd(node); 876 return ReduceJSAdd(node);
967 case IrOpcode::kJSSubtract: 877 case IrOpcode::kJSSubtract:
968 return ReduceNumberBinop(node, simplified()->NumberSubtract()); 878 return ReduceNumberBinop(node, simplified()->NumberSubtract());
969 case IrOpcode::kJSMultiply: 879 case IrOpcode::kJSMultiply:
970 return ReduceJSMultiply(node); 880 return ReduceJSMultiply(node);
971 case IrOpcode::kJSDivide: 881 case IrOpcode::kJSDivide:
972 return ReduceNumberBinop(node, simplified()->NumberDivide()); 882 return ReduceNumberBinop(node, simplified()->NumberDivide());
973 case IrOpcode::kJSModulus: 883 case IrOpcode::kJSModulus:
974 return ReduceNumberBinop(node, simplified()->NumberModulus()); 884 return ReduceNumberBinop(node, simplified()->NumberModulus());
975 case IrOpcode::kJSUnaryNot: { 885 case IrOpcode::kJSUnaryNot:
976 Reduction result = ReduceJSToBooleanInput(node->InputAt(0)); 886 return ReduceJSUnaryNot(node);
977 if (result.Changed()) {
978 // JSUnaryNot(x:boolean) => BooleanNot(x)
979 node = result.replacement();
980 } else {
981 // JSUnaryNot(x) => BooleanNot(JSToBoolean(x))
982 node->set_op(javascript()->ToBoolean());
983 }
984 Node* value = graph()->NewNode(simplified()->BooleanNot(), node);
985 return Replace(value);
986 }
987 case IrOpcode::kJSToBoolean: 887 case IrOpcode::kJSToBoolean:
988 return ReduceJSToBoolean(node); 888 return ReduceJSToBoolean(node);
989 case IrOpcode::kJSToNumber: 889 case IrOpcode::kJSToNumber:
990 return ReduceJSToNumber(node); 890 return ReduceJSToNumber(node);
991 case IrOpcode::kJSToString: 891 case IrOpcode::kJSToString:
992 return ReduceJSToString(node); 892 return ReduceJSToString(node);
993 case IrOpcode::kJSLoadProperty: 893 case IrOpcode::kJSLoadProperty:
994 return ReduceJSLoadProperty(node); 894 return ReduceJSLoadProperty(node);
995 case IrOpcode::kJSStoreProperty: 895 case IrOpcode::kJSStoreProperty:
996 return ReduceJSStoreProperty(node); 896 return ReduceJSStoreProperty(node);
997 case IrOpcode::kJSLoadContext: 897 case IrOpcode::kJSLoadContext:
998 return ReduceJSLoadContext(node); 898 return ReduceJSLoadContext(node);
999 case IrOpcode::kJSStoreContext: 899 case IrOpcode::kJSStoreContext:
1000 return ReduceJSStoreContext(node); 900 return ReduceJSStoreContext(node);
1001 default: 901 default:
1002 break; 902 break;
1003 } 903 }
1004 return NoChange(); 904 return NoChange();
1005 } 905 }
1006 906
1007 907
1008 Node* JSTypedLowering::ConvertToBoolean(Node* input) {
1009 // Avoid inserting too many eager ToBoolean() operations.
1010 Reduction const reduction = ReduceJSToBooleanInput(input);
1011 if (reduction.Changed()) return reduction.replacement();
1012 Node* const conversion = graph()->NewNode(javascript()->ToBoolean(), input,
1013 jsgraph()->NoContextConstant());
1014 InsertConversion(conversion);
1015 return conversion;
1016 }
1017
1018
1019 Node* JSTypedLowering::ConvertToNumber(Node* input) { 908 Node* JSTypedLowering::ConvertToNumber(Node* input) {
1020 DCHECK(NodeProperties::GetBounds(input).upper->Is(Type::PlainPrimitive())); 909 DCHECK(NodeProperties::GetBounds(input).upper->Is(Type::PlainPrimitive()));
1021 // Avoid inserting too many eager ToNumber() operations. 910 // Avoid inserting too many eager ToNumber() operations.
1022 Reduction const reduction = ReduceJSToNumberInput(input); 911 Reduction const reduction = ReduceJSToNumberInput(input);
1023 if (reduction.Changed()) return reduction.replacement(); 912 if (reduction.Changed()) return reduction.replacement();
1024 Node* const conversion = graph()->NewNode(javascript()->ToNumber(), input, 913 Node* const conversion = graph()->NewNode(javascript()->ToNumber(), input,
1025 jsgraph()->NoContextConstant(), 914 jsgraph()->NoContextConstant(),
1026 graph()->start(), graph()->start()); 915 graph()->start(), graph()->start());
1027 InsertConversion(conversion); 916 InsertConversion(conversion);
1028 return conversion; 917 return conversion;
1029 } 918 }
1030 919
1031 920
1032 template <IrOpcode::Value kOpcode> 921 template <IrOpcode::Value kOpcode>
1033 Node* JSTypedLowering::FindConversion(Node* input) { 922 Node* JSTypedLowering::FindConversion(Node* input) {
1034 size_t const input_id = input->id(); 923 size_t const input_id = input->id();
1035 if (input_id < conversions_.size()) { 924 if (input_id < conversions_.size()) {
1036 Node* const conversion = conversions_[input_id]; 925 Node* const conversion = conversions_[input_id];
1037 if (conversion && conversion->opcode() == kOpcode) { 926 if (conversion && conversion->opcode() == kOpcode) {
1038 return conversion; 927 return conversion;
1039 } 928 }
1040 } 929 }
1041 return nullptr; 930 return nullptr;
1042 } 931 }
1043 932
1044 933
1045 void JSTypedLowering::InsertConversion(Node* conversion) { 934 void JSTypedLowering::InsertConversion(Node* conversion) {
1046 DCHECK(conversion->opcode() == IrOpcode::kJSToBoolean || 935 DCHECK(conversion->opcode() == IrOpcode::kJSToNumber);
1047 conversion->opcode() == IrOpcode::kJSToNumber);
1048 size_t const input_id = conversion->InputAt(0)->id(); 936 size_t const input_id = conversion->InputAt(0)->id();
1049 if (input_id >= conversions_.size()) { 937 if (input_id >= conversions_.size()) {
1050 conversions_.resize(2 * input_id + 1); 938 conversions_.resize(2 * input_id + 1);
1051 } 939 }
1052 conversions_[input_id] = conversion; 940 conversions_[input_id] = conversion;
1053 } 941 }
1054 942
1055 943
1056 Node* JSTypedLowering::Word32Shl(Node* const lhs, int32_t const rhs) { 944 Node* JSTypedLowering::Word32Shl(Node* const lhs, int32_t const rhs) {
1057 if (rhs == 0) return lhs; 945 if (rhs == 0) return lhs;
(...skipping 18 matching lines...) Expand all
1076 } 964 }
1077 965
1078 966
1079 MachineOperatorBuilder* JSTypedLowering::machine() const { 967 MachineOperatorBuilder* JSTypedLowering::machine() const {
1080 return jsgraph()->machine(); 968 return jsgraph()->machine();
1081 } 969 }
1082 970
1083 } // namespace compiler 971 } // namespace compiler
1084 } // namespace internal 972 } // namespace internal
1085 } // namespace v8 973 } // namespace v8
OLDNEW
« no previous file with comments | « src/compiler/js-typed-lowering.h ('k') | src/compiler/opcodes.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698