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

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

Issue 23625009: Revert r27232: some checked mode tests fail. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 7 years, 3 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/compiler/dart2js/value_range_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 29 matching lines...) Expand all
40 return new NegateValue(value, this); 40 return new NegateValue(value, this);
41 } 41 }
42 42
43 Range newUnboundRange() { 43 Range newUnboundRange() {
44 return new Range.unbound(this); 44 return new Range.unbound(this);
45 } 45 }
46 46
47 Range newNormalizedRange(Value low, Value up) { 47 Range newNormalizedRange(Value low, Value up) {
48 return new Range.normalize(low, up, this); 48 return new Range.normalize(low, up, this);
49 } 49 }
50
51 Range newMarkerRange() {
52 return new Range(new MarkerValue(false, this),
53 new MarkerValue(true, this),
54 this);
55 }
56 } 50 }
57 51
58 /** 52 /**
59 * A [Value] represents both symbolic values like the value of a 53 * A [Value] represents both symbolic values like the value of a
60 * parameter, or the length of an array, and concrete values, like 54 * parameter, or the length of an array, and concrete values, like
61 * constants. 55 * constants.
62 */ 56 */
63 abstract class Value { 57 abstract class Value {
64 final ValueRangeInfo info; 58 final ValueRangeInfo info;
65 const Value(this.info); 59 const Value(this.info);
(...skipping 22 matching lines...) Expand all
88 if (value.isNegative) return other; 82 if (value.isNegative) return other;
89 return const UnknownValue(); 83 return const UnknownValue();
90 } 84 }
91 85
92 bool get isNegative => false; 86 bool get isNegative => false;
93 bool get isPositive => false; 87 bool get isPositive => false;
94 bool get isZero => false; 88 bool get isZero => false;
95 } 89 }
96 90
97 /** 91 /**
98 * The [MarkerValue] class is used to recognize ranges of loop
99 * updates.
100 */
101 class MarkerValue extends Value {
102 /// If [positive] is true (respectively false), the marker goes
103 /// to [MaxIntValue] (respectively [MinIntValue]) when being added
104 /// to a positive (respectively negative) value.
105 final bool positive;
106
107 const MarkerValue(this.positive, info) : super(info);
108
109 Value operator +(Value other) {
110 if (other.isPositive && positive) return const MaxIntValue();
111 if (other.isNegative && !positive) return const MinIntValue();
112 if (other is IntValue) return this;
113 return const UnknownValue();
114 }
115
116 Value operator -(Value other) {
117 if (other.isPositive && !positive) return const MinIntValue();
118 if (other.isNegative && positive) return const MaxIntValue();
119 if (other is IntValue) return this;
120 return const UnknownValue();
121 }
122 }
123
124 /**
125 * An [IntValue] contains a constant integer value. 92 * An [IntValue] contains a constant integer value.
126 */ 93 */
127 class IntValue extends Value { 94 class IntValue extends Value {
128 final int value; 95 final int value;
129 96
130 const IntValue(this.value, info) : super(info); 97 const IntValue(this.value, info) : super(info);
131 98
132 Value operator +(other) { 99 Value operator +(other) {
133 if (other.isZero) return this; 100 if (other.isZero) return this;
134 if (other is !IntValue) return other + this; 101 if (other is !IntValue) return other + this;
(...skipping 345 matching lines...) Expand 10 before | Expand all | Expand 10 after
480 Range.normalize(Value low, Value up, info) : this( 447 Range.normalize(Value low, Value up, info) : this(
481 low == const UnknownValue() ? const MinIntValue() : low, 448 low == const UnknownValue() ? const MinIntValue() : low,
482 up == const UnknownValue() ? const MaxIntValue() : up, 449 up == const UnknownValue() ? const MaxIntValue() : up,
483 info); 450 info);
484 451
485 Range union(Range other) { 452 Range union(Range other) {
486 return info.newNormalizedRange( 453 return info.newNormalizedRange(
487 lower.min(other.lower), upper.max(other.upper)); 454 lower.min(other.lower), upper.max(other.upper));
488 } 455 }
489 456
490 Range intersection(Range other) { 457 intersection(Range other) {
491 Value low = lower.max(other.lower); 458 Value low = lower.max(other.lower);
492 Value up = upper.min(other.upper); 459 Value up = upper.min(other.upper);
493 // If we could not compute max or min, pick a value in the two 460 // If we could not compute max or min, pick a value in the two
494 // ranges, with priority to [IntValue]s because they are simpler. 461 // ranges, with priority to [IntValue]s because they are simpler.
495 if (low == const UnknownValue()) { 462 if (low == const UnknownValue()) {
496 if (lower is IntValue) low = lower; 463 if (lower is IntValue) low = lower;
497 else if (other.lower is IntValue) low = other.lower; 464 else if (other.lower is IntValue) low = other.lower;
498 else low = lower; 465 else low = lower;
499 } 466 }
500 if (up == const UnknownValue()) { 467 if (up == const UnknownValue()) {
(...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after
647 } 614 }
648 615
649 Range visitPhi(HPhi phi) { 616 Range visitPhi(HPhi phi) {
650 if (!phi.isInteger()) return info.newUnboundRange(); 617 if (!phi.isInteger()) return info.newUnboundRange();
651 // Some phases may replace instructions that change the inputs of 618 // Some phases may replace instructions that change the inputs of
652 // this phi. Only the [SsaTypesPropagation] phase will update the 619 // this phi. Only the [SsaTypesPropagation] phase will update the
653 // phi type. Play it safe by assuming the [SsaTypesPropagation] 620 // phi type. Play it safe by assuming the [SsaTypesPropagation]
654 // phase is not necessarily run before the [ValueRangeAnalyzer]. 621 // phase is not necessarily run before the [ValueRangeAnalyzer].
655 if (phi.inputs.any((i) => !i.isInteger())) return info.newUnboundRange(); 622 if (phi.inputs.any((i) => !i.isInteger())) return info.newUnboundRange();
656 if (phi.block.isLoopHeader()) { 623 if (phi.block.isLoopHeader()) {
657 Range range = new LoopUpdateRecognizer(ranges, info).run(phi); 624 Range range = tryInferLoopPhiRange(phi);
658 if (range == null) return info.newUnboundRange(); 625 if (range == null) return info.newUnboundRange();
659 return range; 626 return range;
660 } 627 }
661 628
662 Range range = ranges[phi.inputs[0]]; 629 Range range = ranges[phi.inputs[0]];
663 for (int i = 1; i < phi.inputs.length; i++) { 630 for (int i = 1; i < phi.inputs.length; i++) {
664 range = range.union(ranges[phi.inputs[i]]); 631 range = range.union(ranges[phi.inputs[i]]);
665 } 632 }
666 return range; 633 return range;
667 } 634 }
668 635
636 Range tryInferLoopPhiRange(HPhi phi) {
637 HInstruction update = phi.inputs[1];
638 return update.accept(new LoopUpdateRecognizer(phi, ranges, info));
639 }
640
669 Range visitConstant(HConstant constant) { 641 Range visitConstant(HConstant constant) {
670 if (!constant.isInteger()) return info.newUnboundRange(); 642 if (!constant.isInteger()) return info.newUnboundRange();
671 IntConstant constantInt = constant.constant; 643 IntConstant constantInt = constant.constant;
672 Value value = info.newIntValue(constantInt.value); 644 Value value = info.newIntValue(constantInt.value);
673 return info.newNormalizedRange(value, value); 645 return info.newNormalizedRange(value, value);
674 } 646 }
675 647
676 Range visitFieldGet(HFieldGet fieldGet) { 648 Range visitFieldGet(HFieldGet fieldGet) {
677 if (!fieldGet.isInteger()) return info.newUnboundRange(); 649 if (!fieldGet.isInteger()) return info.newUnboundRange();
678 if (!fieldGet.receiver.isIndexable(compiler)) { 650 if (!fieldGet.receiver.isIndexable(compiler)) {
(...skipping 250 matching lines...) Expand 10 before | Expand all | Expand 10 after
929 901
930 return info.newUnboundRange(); 902 return info.newUnboundRange();
931 } 903 }
932 904
933 Range visitRangeConversion(HRangeConversion conversion) { 905 Range visitRangeConversion(HRangeConversion conversion) {
934 return ranges[conversion]; 906 return ranges[conversion];
935 } 907 }
936 } 908 }
937 909
938 /** 910 /**
939 * Tries to find a range for the update instruction of a loop phi. 911 * Recognizes a number of patterns in a loop update instruction and
912 * tries to infer a range for the loop phi.
940 */ 913 */
941 class LoopUpdateRecognizer extends HBaseVisitor { 914 class LoopUpdateRecognizer extends HBaseVisitor {
915 final HPhi loopPhi;
942 final Map<HInstruction, Range> ranges; 916 final Map<HInstruction, Range> ranges;
943 final ValueRangeInfo info; 917 final ValueRangeInfo info;
944 LoopUpdateRecognizer(this.ranges, this.info); 918 LoopUpdateRecognizer(this.loopPhi, this.ranges, this.info);
945 919
946 Range run(HPhi loopPhi) { 920 Range visitAdd(HAdd operation) {
947 // Create a marker range for the loop phi, so that if the update 921 Range range = getRangeForRecognizableOperation(operation);
948 // uses the loop phi, it has a range to use. 922 if (range == null) return info.newUnboundRange();
949 ranges[loopPhi] = info.newMarkerRange(); 923 Range initial = ranges[loopPhi.inputs[0]];
950 Range updateRange = visit(loopPhi.inputs[1]); 924 if (range.isPositive) {
951 ranges[loopPhi] = null; 925 return info.newNormalizedRange(initial.lower, const MaxIntValue());
952 if (updateRange == null) return null; 926 } else if (range.isNegative) {
953 Range startRange = ranges[loopPhi.inputs[0]]; 927 return info.newNormalizedRange(const MinIntValue(), initial.upper);
954 Value low = updateRange.lower is MarkerValue 928 }
955 ? startRange.lower 929 return info.newUnboundRange();
956 : updateRange.lower;
957 Value up = updateRange.upper is MarkerValue
958 ? startRange.upper
959 : updateRange.upper;
960 return info.newNormalizedRange(low, up);
961 } 930 }
962 931
963 Range visit(HInstruction instruction) { 932 Range visitSubtract(HSubtract operation) {
964 if (!instruction.isInteger()) return null; 933 Range range = getRangeForRecognizableOperation(operation);
965 if (ranges[instruction] != null) return ranges[instruction]; 934 if (range == null) return info.newUnboundRange();
966 return instruction.accept(this); 935 Range initial = ranges[loopPhi.inputs[0]];
936 if (range.isPositive) {
937 return info.newNormalizedRange(const MinIntValue(), initial.upper);
938 } else if (range.isNegative) {
939 return info.newNormalizedRange(initial.lower, const MaxIntValue());
940 }
941 return info.newUnboundRange();
967 } 942 }
968 943
969 Range visitPhi(HPhi phi) { 944 Range visitPhi(HPhi phi) {
970 // If the update of a loop phi involves another loop phi, we give
971 // up.
972 if (phi.block.isLoopHeader()) return null;
973 Range phiRange; 945 Range phiRange;
974 for (HInstruction input in phi.inputs) { 946 for (HInstruction input in phi.inputs) {
975 Range inputRange = visit(input); 947 HInstruction instruction = unwrap(input);
948 // If one of the inputs is the loop phi, then we're only
949 // interested in the other inputs: a loop phi feeding itself means
950 // it is not being updated.
951 if (instruction == loopPhi) continue;
952
953 // If another loop phi is involved, it's too complex to analyze.
954 if (instruction is HPhi && instruction.block.isLoopHeader()) return null;
955
956 Range inputRange = instruction.accept(this);
976 if (inputRange == null) return null; 957 if (inputRange == null) return null;
977 if (phiRange == null) { 958 if (phiRange == null) {
978 phiRange = inputRange; 959 phiRange = inputRange;
979 } else { 960 } else {
980 phiRange = phiRange.union(inputRange); 961 phiRange = phiRange.union(inputRange);
981 } 962 }
982 } 963 }
983 return phiRange; 964 return phiRange;
984 } 965 }
985 966
986 Range visitCheck(HCheck instruction) { 967 /**
987 return visit(instruction.checkedInput); 968 * If [operation] is recognizable, returns the inferred range.
969 * Otherwise returns [null].
970 */
971 Range getRangeForRecognizableOperation(HBinaryArithmetic operation) {
972 if (!operation.left.isInteger()) return null;
973 if (!operation.right.isInteger()) return null;
974 HInstruction left = unwrap(operation.left);
975 HInstruction right = unwrap(operation.right);
976 // We only recognize operations that operate on the loop phi.
977 bool isLeftLoopPhi = (left == loopPhi);
978 bool isRightLoopPhi = (right == loopPhi);
979 if (!isLeftLoopPhi && !isRightLoopPhi) return null;
980
981 var other = isLeftLoopPhi ? right : left;
982 // If the analysis already computed range for the update, use it.
983 if (ranges[other] != null) return ranges[other];
984
985 // We currently only handle constants in updates if the
986 // update does not have a range.
987 if (other.isConstant()) {
988 Value value = info.newIntValue(other.constant.value);
989 return info.newNormalizedRange(value, value);
990 }
991 return null;
988 } 992 }
989 993
990 Range visitAdd(HAdd operation) { 994 /**
991 return handleBinaryOperation(operation); 995 * [HCheck] instructions may check the loop phi. Since we only
992 } 996 * recognize updates on the loop phi, we must [unwrap] the [HCheck]
993 997 * instruction to check if it references the loop phi.
994 Range visitSubtract(HSubtract operation) { 998 */
995 return handleBinaryOperation(operation); 999 HInstruction unwrap(instruction) {
996 } 1000 if (instruction is HCheck) return unwrap(instruction.checkedInput);
997 1001 // [HPhi] might have two different [HCheck] instructions as
998 Range handleBinaryOperation(HBinaryArithmetic instruction) { 1002 // inputs, checking the same instruction.
999 Range leftRange = visit(instruction.left); 1003 if (instruction is HPhi && !instruction.block.isLoopHeader()) {
1000 Range rightRange = visit(instruction.right); 1004 HInstruction result = unwrap(instruction.inputs[0]);
1001 if (leftRange == null || rightRange == null) return null; 1005 for (int i = 1; i < instruction.inputs.length; i++) {
1002 BinaryOperation operation = instruction.operation(info.constantSystem); 1006 if (result != unwrap(instruction.inputs[i])) return instruction;
1003 return operation.apply(leftRange, rightRange); 1007 }
1008 return result;
1009 }
1010 return instruction;
1004 } 1011 }
1005 } 1012 }
OLDNEW
« no previous file with comments | « no previous file | tests/compiler/dart2js/value_range_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698