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

Side by Side Diff: sdk/lib/_internal/compiler/implementation/ssa/value_range_analyzer.dart

Issue 12788003: Always normalize a Range. The analysis does not work when it sees a range with unknown as bounds. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 7 years, 9 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 | Annotate | Revision Log
« no previous file with comments | « no previous file | tests/language/value_range3_test.dart » ('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 (c) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 part of ssa; 5 part of ssa;
6 6
7 7
8 class ValueRangeInfo { 8 class ValueRangeInfo {
9 final ConstantSystem constantSystem; 9 final ConstantSystem constantSystem;
10 10
(...skipping 22 matching lines...) Expand all
33 } 33 }
34 34
35 Value newSubtractValue(Value left, Value right) { 35 Value newSubtractValue(Value left, Value right) {
36 return new SubtractValue(left, right, this); 36 return new SubtractValue(left, right, this);
37 } 37 }
38 38
39 Value newNegateValue(Value value) { 39 Value newNegateValue(Value value) {
40 return new NegateValue(value, this); 40 return new NegateValue(value, this);
41 } 41 }
42 42
43 Range newRange(Value low, Value up) {
44 return new Range(low, up, this);
45 }
46
47 Range newUnboundRange() { 43 Range newUnboundRange() {
48 return new Range.unbound(this); 44 return new Range.unbound(this);
49 } 45 }
50 46
51 Range newNormalizedRange(Value low, Value up) { 47 Range newNormalizedRange(Value low, Value up) {
52 return new Range.normalize(low, up, this); 48 return new Range.normalize(low, up, this);
53 } 49 }
54 } 50 }
55 51
56 /** 52 /**
(...skipping 363 matching lines...) Expand 10 before | Expand all | Expand 10 after
420 416
421 /** 417 /**
422 * A [Range] represents the possible integer values an instruction 418 * A [Range] represents the possible integer values an instruction
423 * can have, from its [lower] bound to its [upper] bound, both 419 * can have, from its [lower] bound to its [upper] bound, both
424 * included. 420 * included.
425 */ 421 */
426 class Range { 422 class Range {
427 final Value lower; 423 final Value lower;
428 final Value upper; 424 final Value upper;
429 final ValueRangeInfo info; 425 final ValueRangeInfo info;
430 Range(this.lower, this.upper, this.info); 426 Range(this.lower, this.upper, this.info) {
427 assert(lower != const UnknownValue());
428 assert(upper != const UnknownValue());
429 }
431 430
432 Range.unbound(info) : this(const MinIntValue(), const MaxIntValue(), info); 431 Range.unbound(info) : this(const MinIntValue(), const MaxIntValue(), info);
433 432
434 /** 433 /**
435 * Checks if the given values are unknown, and creates a 434 * Checks if the given values are unknown, and creates a
436 * range that does not have any unknown values. 435 * range that does not have any unknown values.
437 */ 436 */
438 Range.normalize(Value low, Value up, info) : this( 437 Range.normalize(Value low, Value up, info) : this(
439 low == const UnknownValue() ? const MinIntValue() : low, 438 low == const UnknownValue() ? const MinIntValue() : low,
440 up == const UnknownValue() ? const MaxIntValue() : up, 439 up == const UnknownValue() ? const MaxIntValue() : up,
(...skipping 12 matching lines...) Expand all
453 if (low == const UnknownValue()) { 452 if (low == const UnknownValue()) {
454 if (lower is IntValue) low = lower; 453 if (lower is IntValue) low = lower;
455 else if (other.lower is IntValue) low = other.lower; 454 else if (other.lower is IntValue) low = other.lower;
456 else low = lower; 455 else low = lower;
457 } 456 }
458 if (up == const UnknownValue()) { 457 if (up == const UnknownValue()) {
459 if (upper is IntValue) up = upper; 458 if (upper is IntValue) up = upper;
460 else if (other.upper is IntValue) up = other.upper; 459 else if (other.upper is IntValue) up = other.upper;
461 else up = upper; 460 else up = upper;
462 } 461 }
463 return info.newRange(low, up); 462 return info.newNormalizedRange(low, up);
464 } 463 }
465 464
466 Range operator +(Range other) { 465 Range operator +(Range other) {
467 return info.newNormalizedRange(lower + other.lower, upper + other.upper); 466 return info.newNormalizedRange(lower + other.lower, upper + other.upper);
468 } 467 }
469 468
470 Range operator -(Range other) { 469 Range operator -(Range other) {
471 return info.newNormalizedRange(lower - other.upper, upper - other.lower); 470 return info.newNormalizedRange(lower - other.upper, upper - other.lower);
472 } 471 }
473 472
474 Range operator -() { 473 Range operator -() {
475 return info.newNormalizedRange(-upper, -lower); 474 return info.newNormalizedRange(-upper, -lower);
476 } 475 }
477 476
478 Range operator &(Range other) { 477 Range operator &(Range other) {
479 if (isSingleValue 478 if (isSingleValue
480 && other.isSingleValue 479 && other.isSingleValue
481 && lower is IntValue 480 && lower is IntValue
482 && other.lower is IntValue) { 481 && other.lower is IntValue) {
483 return info.newRange(lower & other.lower, upper & other.upper); 482 return info.newNormalizedRange(lower & other.lower, upper & other.upper);
484 } 483 }
485 if (isPositive && other.isPositive) { 484 if (isPositive && other.isPositive) {
486 Value up = upper.min(other.upper); 485 Value up = upper.min(other.upper);
487 if (up == const UnknownValue()) { 486 if (up == const UnknownValue()) {
488 // If we could not find a trivial bound, just try to use the 487 // If we could not find a trivial bound, just try to use the
489 // one that is an int. 488 // one that is an int.
490 up = upper is IntValue ? upper : other.upper; 489 up = upper is IntValue ? upper : other.upper;
491 // Make sure we get the same upper bound, whether it's a & b 490 // Make sure we get the same upper bound, whether it's a & b
492 // or b & a. 491 // or b & a.
493 if (up is! IntValue && upper != other.upper) up = const MaxIntValue(); 492 if (up is! IntValue && upper != other.upper) up = const MaxIntValue();
494 } 493 }
495 return info.newRange(info.intZero, up); 494 return info.newNormalizedRange(info.intZero, up);
496 } else if (isPositive) { 495 } else if (isPositive) {
497 return info.newRange(info.intZero, upper); 496 return info.newNormalizedRange(info.intZero, upper);
498 } else if (other.isPositive) { 497 } else if (other.isPositive) {
499 return info.newRange(info.intZero, other.upper); 498 return info.newNormalizedRange(info.intZero, other.upper);
500 } else { 499 } else {
501 return info.newUnboundRange(); 500 return info.newUnboundRange();
502 } 501 }
503 } 502 }
504 503
505 bool operator ==(other) { 504 bool operator ==(other) {
506 if (other is! Range) return false; 505 if (other is! Range) return false;
507 return other.lower == lower && other.upper == upper; 506 return other.lower == lower && other.upper == upper;
508 } 507 }
509 508
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after
591 block.forEachInstruction(visit); 590 block.forEachInstruction(visit);
592 } 591 }
593 592
594 Range visitInstruction(HInstruction instruction) { 593 Range visitInstruction(HInstruction instruction) {
595 return info.newUnboundRange(); 594 return info.newUnboundRange();
596 } 595 }
597 596
598 Range visitParameterValue(HParameterValue parameter) { 597 Range visitParameterValue(HParameterValue parameter) {
599 if (!parameter.isInteger()) return info.newUnboundRange(); 598 if (!parameter.isInteger()) return info.newUnboundRange();
600 Value value = info.newInstructionValue(parameter); 599 Value value = info.newInstructionValue(parameter);
601 return info.newRange(value, value); 600 return info.newNormalizedRange(value, value);
602 } 601 }
603 602
604 Range visitPhi(HPhi phi) { 603 Range visitPhi(HPhi phi) {
605 if (!phi.isInteger()) return info.newUnboundRange(); 604 if (!phi.isInteger()) return info.newUnboundRange();
606 if (phi.block.isLoopHeader()) { 605 if (phi.block.isLoopHeader()) {
607 Range range = tryInferLoopPhiRange(phi); 606 Range range = tryInferLoopPhiRange(phi);
608 if (range == null) return info.newUnboundRange(); 607 if (range == null) return info.newUnboundRange();
609 return range; 608 return range;
610 } 609 }
611 610
612 Range range = ranges[phi.inputs[0]]; 611 Range range = ranges[phi.inputs[0]];
613 for (int i = 1; i < phi.inputs.length; i++) { 612 for (int i = 1; i < phi.inputs.length; i++) {
614 range = range.union(ranges[phi.inputs[i]]); 613 range = range.union(ranges[phi.inputs[i]]);
615 } 614 }
616 return range; 615 return range;
617 } 616 }
618 617
619 Range tryInferLoopPhiRange(HPhi phi) { 618 Range tryInferLoopPhiRange(HPhi phi) {
620 HInstruction update = phi.inputs[1]; 619 HInstruction update = phi.inputs[1];
621 return update.accept(new LoopUpdateRecognizer(phi, ranges, info)); 620 return update.accept(new LoopUpdateRecognizer(phi, ranges, info));
622 } 621 }
623 622
624 Range visitConstant(HConstant constant) { 623 Range visitConstant(HConstant constant) {
625 if (!constant.isInteger()) return info.newUnboundRange(); 624 if (!constant.isInteger()) return info.newUnboundRange();
626 IntConstant constantInt = constant.constant; 625 IntConstant constantInt = constant.constant;
627 Value value = info.newIntValue(constantInt.value); 626 Value value = info.newIntValue(constantInt.value);
628 return info.newRange(value, value); 627 return info.newNormalizedRange(value, value);
629 } 628 }
630 629
631 Range visitFieldGet(HFieldGet fieldGet) { 630 Range visitFieldGet(HFieldGet fieldGet) {
632 if (!fieldGet.isInteger()) return info.newUnboundRange(); 631 if (!fieldGet.isInteger()) return info.newUnboundRange();
633 if (!fieldGet.receiver.isIndexablePrimitive()) { 632 if (!fieldGet.receiver.isIndexablePrimitive()) {
634 return visitInstruction(fieldGet); 633 return visitInstruction(fieldGet);
635 } 634 }
636 LengthValue value = info.newLengthValue(fieldGet); 635 LengthValue value = info.newLengthValue(fieldGet);
637 // We know this range is above zero. To simplify the analysis, we 636 // We know this range is above zero. To simplify the analysis, we
638 // put the zero value as the lower bound of this range. This 637 // put the zero value as the lower bound of this range. This
639 // allows to easily remove the second bound check in the following 638 // allows to easily remove the second bound check in the following
640 // expression: a[1] + a[0]. 639 // expression: a[1] + a[0].
641 return info.newRange(info.intZero, value); 640 return info.newNormalizedRange(info.intZero, value);
642 } 641 }
643 642
644 Range visitBoundsCheck(HBoundsCheck check) { 643 Range visitBoundsCheck(HBoundsCheck check) {
645 // Save the next instruction, in case the check gets removed. 644 // Save the next instruction, in case the check gets removed.
646 HInstruction next = check.next; 645 HInstruction next = check.next;
647 Range indexRange = ranges[check.index]; 646 Range indexRange = ranges[check.index];
648 Range lengthRange = ranges[check.length]; 647 Range lengthRange = ranges[check.length];
649 assert(check.index.isInteger()); 648 assert(check.index.isInteger());
650 assert(check.length.isInteger()); 649 assert(check.length.isInteger());
651 650
(...skipping 22 matching lines...) Expand all
674 check.staticChecks = HBoundsCheck.ALWAYS_BELOW_LENGTH; 673 check.staticChecks = HBoundsCheck.ALWAYS_BELOW_LENGTH;
675 } 674 }
676 675
677 if (indexRange.isPositive) { 676 if (indexRange.isPositive) {
678 // If the test passes, we know the lower bound of the length is 677 // If the test passes, we know the lower bound of the length is
679 // greater or equal than the lower bound of the index. 678 // greater or equal than the lower bound of the index.
680 Value low = lengthRange.lower.max(indexRange.lower); 679 Value low = lengthRange.lower.max(indexRange.lower);
681 if (low != const UnknownValue()) { 680 if (low != const UnknownValue()) {
682 HInstruction instruction = 681 HInstruction instruction =
683 createRangeConversion(next, check.length); 682 createRangeConversion(next, check.length);
684 ranges[instruction] = info.newRange(low, lengthRange.upper); 683 ranges[instruction] = info.newNormalizedRange(low, lengthRange.upper);
685 } 684 }
686 } 685 }
687 686
688 if (!belowLength) { 687 if (!belowLength) {
689 // Update the range of the index if using the maximum index 688 // Update the range of the index if using the maximum index
690 // narrows it. 689 // narrows it.
691 Range newIndexRange = indexRange.intersection( 690 Range newIndexRange = indexRange.intersection(
692 info.newRange(info.intZero, maxIndex)); 691 info.newNormalizedRange(info.intZero, maxIndex));
693 if (indexRange == newIndexRange) return indexRange; 692 if (indexRange == newIndexRange) return indexRange;
694 HInstruction instruction = createRangeConversion(next, check.index); 693 HInstruction instruction = createRangeConversion(next, check.index);
695 ranges[instruction] = newIndexRange; 694 ranges[instruction] = newIndexRange;
696 return newIndexRange; 695 return newIndexRange;
697 } 696 }
698 697
699 return indexRange; 698 return indexRange;
700 } 699 }
701 700
702 Range visitRelational(HRelational relational) { 701 Range visitRelational(HRelational relational) {
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
750 if (!node.isInteger()) return info.newUnboundRange(); 749 if (!node.isInteger()) return info.newUnboundRange();
751 HInstruction right = node.right; 750 HInstruction right = node.right;
752 HInstruction left = node.left; 751 HInstruction left = node.left;
753 if (left.isInteger() && right.isInteger()) { 752 if (left.isInteger() && right.isInteger()) {
754 return ranges[left] & ranges[right]; 753 return ranges[left] & ranges[right];
755 } 754 }
756 755
757 Range tryComputeRange(HInstruction instruction) { 756 Range tryComputeRange(HInstruction instruction) {
758 Range range = ranges[instruction]; 757 Range range = ranges[instruction];
759 if (range.isPositive) { 758 if (range.isPositive) {
760 return info.newRange(info.intZero, range.upper); 759 return info.newNormalizedRange(info.intZero, range.upper);
761 } else if (range.isNegative) { 760 } else if (range.isNegative) {
762 return info.newRange(range.lower, info.intZero); 761 return info.newNormalizedRange(range.lower, info.intZero);
763 } 762 }
764 return info.newUnboundRange(); 763 return info.newUnboundRange();
765 } 764 }
766 765
767 if (left.isInteger()) { 766 if (left.isInteger()) {
768 return tryComputeRange(left); 767 return tryComputeRange(left);
769 } else if (right.isInteger()) { 768 } else if (right.isInteger()) {
770 return tryComputeRange(right); 769 return tryComputeRange(right);
771 } 770 }
772 return info.newUnboundRange(); 771 return info.newUnboundRange();
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
805 } else { 804 } else {
806 return null; 805 return null;
807 } 806 }
808 } 807 }
809 808
810 Range computeConstrainedRange(BinaryOperation operation, 809 Range computeConstrainedRange(BinaryOperation operation,
811 Range leftRange, 810 Range leftRange,
812 Range rightRange) { 811 Range rightRange) {
813 Range range; 812 Range range;
814 if (operation == const LessOperation()) { 813 if (operation == const LessOperation()) {
815 range = info.newRange( 814 range = info.newNormalizedRange(
816 const MinIntValue(), rightRange.upper - info.intOne); 815 const MinIntValue(), rightRange.upper - info.intOne);
817 } else if (operation == const LessEqualOperation()) { 816 } else if (operation == const LessEqualOperation()) {
818 range = info.newRange(const MinIntValue(), rightRange.upper); 817 range = info.newNormalizedRange(const MinIntValue(), rightRange.upper);
819 } else if (operation == const GreaterOperation()) { 818 } else if (operation == const GreaterOperation()) {
820 range = info.newRange( 819 range = info.newNormalizedRange(
821 rightRange.lower + info.intOne, const MaxIntValue()); 820 rightRange.lower + info.intOne, const MaxIntValue());
822 } else if (operation == const GreaterEqualOperation()) { 821 } else if (operation == const GreaterEqualOperation()) {
823 range = info.newRange(rightRange.lower, const MaxIntValue()); 822 range = info.newNormalizedRange(rightRange.lower, const MaxIntValue());
824 } else { 823 } else {
825 range = info.newUnboundRange(); 824 range = info.newUnboundRange();
826 } 825 }
827 return range.intersection(leftRange); 826 return range.intersection(leftRange);
828 } 827 }
829 828
830 Range visitConditionalBranch(HConditionalBranch branch) { 829 Range visitConditionalBranch(HConditionalBranch branch) {
831 var condition = branch.condition; 830 var condition = branch.condition;
832 // TODO(ngeoffray): Handle complex conditions. 831 // TODO(ngeoffray): Handle complex conditions.
833 if (condition is !HRelational) return info.newUnboundRange(); 832 if (condition is !HRelational) return info.newUnboundRange();
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
899 final HPhi loopPhi; 898 final HPhi loopPhi;
900 final Map<HInstruction, Range> ranges; 899 final Map<HInstruction, Range> ranges;
901 final ValueRangeInfo info; 900 final ValueRangeInfo info;
902 LoopUpdateRecognizer(this.loopPhi, this.ranges, this.info); 901 LoopUpdateRecognizer(this.loopPhi, this.ranges, this.info);
903 902
904 Range visitAdd(HAdd operation) { 903 Range visitAdd(HAdd operation) {
905 Range range = getRangeForRecognizableOperation(operation); 904 Range range = getRangeForRecognizableOperation(operation);
906 if (range == null) return info.newUnboundRange(); 905 if (range == null) return info.newUnboundRange();
907 Range initial = ranges[loopPhi.inputs[0]]; 906 Range initial = ranges[loopPhi.inputs[0]];
908 if (range.isPositive) { 907 if (range.isPositive) {
909 return info.newRange(initial.lower, const MaxIntValue()); 908 return info.newNormalizedRange(initial.lower, const MaxIntValue());
910 } else if (range.isNegative) { 909 } else if (range.isNegative) {
911 return info.newRange(const MinIntValue(), initial.upper); 910 return info.newNormalizedRange(const MinIntValue(), initial.upper);
912 } 911 }
913 return info.newUnboundRange(); 912 return info.newUnboundRange();
914 } 913 }
915 914
916 Range visitSubtract(HSubtract operation) { 915 Range visitSubtract(HSubtract operation) {
917 Range range = getRangeForRecognizableOperation(operation); 916 Range range = getRangeForRecognizableOperation(operation);
918 if (range == null) return info.newUnboundRange(); 917 if (range == null) return info.newUnboundRange();
919 Range initial = ranges[loopPhi.inputs[0]]; 918 Range initial = ranges[loopPhi.inputs[0]];
920 if (range.isPositive) { 919 if (range.isPositive) {
921 return info.newRange(const MinIntValue(), initial.upper); 920 return info.newNormalizedRange(const MinIntValue(), initial.upper);
922 } else if (range.isNegative) { 921 } else if (range.isNegative) {
923 return info.newRange(initial.lower, const MaxIntValue()); 922 return info.newNormalizedRange(initial.lower, const MaxIntValue());
924 } 923 }
925 return info.newUnboundRange(); 924 return info.newUnboundRange();
926 } 925 }
927 926
928 Range visitPhi(HPhi phi) { 927 Range visitPhi(HPhi phi) {
929 Range phiRange; 928 Range phiRange;
930 for (HInstruction input in phi.inputs) { 929 for (HInstruction input in phi.inputs) {
931 HInstruction instruction = unwrap(input); 930 HInstruction instruction = unwrap(input);
932 // If one of the inputs is the loop phi, then we're only 931 // If one of the inputs is the loop phi, then we're only
933 // interested in the other inputs: a loop phi feeding itself means 932 // interested in the other inputs: a loop phi feeding itself means
(...skipping 29 matching lines...) Expand all
963 if (!isLeftLoopPhi && !isRightLoopPhi) return null; 962 if (!isLeftLoopPhi && !isRightLoopPhi) return null;
964 963
965 var other = isLeftLoopPhi ? right : left; 964 var other = isLeftLoopPhi ? right : left;
966 // If the analysis already computed range for the update, use it. 965 // If the analysis already computed range for the update, use it.
967 if (ranges[other] != null) return ranges[other]; 966 if (ranges[other] != null) return ranges[other];
968 967
969 // We currently only handle constants in updates if the 968 // We currently only handle constants in updates if the
970 // update does not have a range. 969 // update does not have a range.
971 if (other.isConstant()) { 970 if (other.isConstant()) {
972 Value value = info.newIntValue(other.constant.value); 971 Value value = info.newIntValue(other.constant.value);
973 return info.newRange(value, value); 972 return info.newNormalizedRange(value, value);
974 } 973 }
975 return null; 974 return null;
976 } 975 }
977 976
978 /** 977 /**
979 * [HCheck] instructions may check the loop phi. Since we only 978 * [HCheck] instructions may check the loop phi. Since we only
980 * recognize updates on the loop phi, we must [unwrap] the [HCheck] 979 * recognize updates on the loop phi, we must [unwrap] the [HCheck]
981 * instruction to check if it references the loop phi. 980 * instruction to check if it references the loop phi.
982 */ 981 */
983 HInstruction unwrap(instruction) { 982 HInstruction unwrap(instruction) {
984 if (instruction is HCheck) return unwrap(instruction.checkedInput); 983 if (instruction is HCheck) return unwrap(instruction.checkedInput);
985 // [HPhi] might have two different [HCheck] instructions as 984 // [HPhi] might have two different [HCheck] instructions as
986 // inputs, checking the same instruction. 985 // inputs, checking the same instruction.
987 if (instruction is HPhi && !instruction.block.isLoopHeader()) { 986 if (instruction is HPhi && !instruction.block.isLoopHeader()) {
988 HInstruction result = unwrap(instruction.inputs[0]); 987 HInstruction result = unwrap(instruction.inputs[0]);
989 for (int i = 1; i < instruction.inputs.length; i++) { 988 for (int i = 1; i < instruction.inputs.length; i++) {
990 if (result != unwrap(instruction.inputs[i])) return instruction; 989 if (result != unwrap(instruction.inputs[i])) return instruction;
991 } 990 }
992 return result; 991 return result;
993 } 992 }
994 return instruction; 993 return instruction;
995 } 994 }
996 } 995 }
OLDNEW
« no previous file with comments | « no previous file | tests/language/value_range3_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698