| OLD | NEW |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 } |
| OLD | NEW |