Skip to content

Commit 3c0b54f

Browse files
committed
Review cleanups
1 parent d483b6d commit 3c0b54f

File tree

3 files changed

+128
-128
lines changed

3 files changed

+128
-128
lines changed

compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/alloc/lsra/Interval.java

Lines changed: 126 additions & 127 deletions
Original file line numberDiff line numberDiff line change
@@ -471,7 +471,10 @@ public String toString() {
471471
Interval next;
472472

473473
/**
474-
* Link to next spill interval in a list of intervals that ends with {@code null}.
474+
* Link to the next spill interval in a list of intervals that ends with {@code null}. This
475+
* field is only valid when iterating intervals starting from
476+
* {@link LinearScanWalker#spillIntervals}. Only the head of the list of cleared so this field
477+
* can contain stale values.
475478
*/
476479
Interval spillNext;
477480

@@ -655,8 +658,14 @@ void removeFirstUsePos() {
655658
private int rangePairLength;
656659

657660
/**
658-
* The list [{@code from}, {@code to}) pairs representing a range of integers from a start
661+
* The list of [{@code from}, {@code to}) pairs representing a range of integers from a start
659662
* (inclusive) to an end (exclusive).
663+
* <p>
664+
* All values are positive and the ranges are always sorted such that {@code from} is less than
665+
* {@code to} and {@code to} is less than the next {@code from}. This means that the integers in
666+
* the array are sorted and disjoint. The {@code to} of a range will never equal the
667+
* {@code from} of the next range as during interval construction such ranges are merged into a
668+
* single range. {@link #rangePairLength} is portion of this array that is valid.
660669
*/
661670
private int[] rangePairs;
662671

@@ -683,6 +692,11 @@ boolean isEmpty() {
683692
private void ensureCapacity(int minCapacity) {
684693
if (minCapacity > rangePairs.length) {
685694
int oldCapacity = rangePairs.length;
695+
/*
696+
* This is basically the ArrayList expansion policy but in practice these arrays are
697+
* relatively short so the policy isn't critical. Roughly 30% of intervals have a single
698+
* element and 90% have less than 10.
699+
*/
686700
rangePairs = Arrays.copyOf(rangePairs, oldCapacity + Math.max(minCapacity - oldCapacity, oldCapacity >> 1));
687701
}
688702
}
@@ -741,34 +755,36 @@ public String getRangesAsString() {
741755
}
742756

743757
/**
744-
* Copy the content of {@code other} into this list starting after splitPos.
758+
* Splits this interval at a specified position, creating a new child interval and updating the
759+
* range information for both this interval and the new child.
745760
*/
746-
void split(Interval other, int splitPos) {
761+
Interval createSplit(int splitPos, LinearScan allocator) {
762+
Interval newInterval = newSplitChild(allocator);
747763
// split the ranges
748764
int curRangeIndex = 0;
749-
while (curRangeIndex != other.rangePairLength && other.to(curRangeIndex) <= splitPos) {
765+
while (curRangeIndex != rangePairLength && to(curRangeIndex) <= splitPos) {
750766
curRangeIndex += 2;
751767
}
752-
assert !(curRangeIndex == other.rangePairLength) : "split interval after end of last range";
768+
assert !(curRangeIndex == rangePairLength) : "split interval after end of last range";
753769

754-
if (other.from(curRangeIndex) < splitPos) {
770+
if (from(curRangeIndex) < splitPos) {
755771
// Splitting a pair
756-
rangePairs = Arrays.copyOfRange(other.rangePairs, curRangeIndex, other.rangePairLength);
757-
rangePairLength = rangePairs.length;
758-
if (rangePairLength > 0) {
759-
rangePairs[0] = splitPos;
772+
newInterval.rangePairs = Arrays.copyOfRange(rangePairs, curRangeIndex, rangePairLength);
773+
newInterval.rangePairLength = newInterval.rangePairs.length;
774+
if (newInterval.rangePairLength > 0) {
775+
newInterval.rangePairs[0] = splitPos;
760776
}
761-
other.rangePairLength = curRangeIndex + 2;
762-
other.rangePairs[other.rangePairLength - 1] = splitPos;
777+
rangePairLength = curRangeIndex + 2;
778+
rangePairs[rangePairLength - 1] = splitPos;
763779
} else {
764780
// Splitting between two ranges
765-
rangePairs = Arrays.copyOfRange(other.rangePairs, curRangeIndex, other.rangePairLength);
766-
rangePairLength = rangePairs.length;
767-
other.rangePairLength = curRangeIndex;
781+
newInterval.rangePairs = Arrays.copyOfRange(rangePairs, curRangeIndex, rangePairLength);
782+
newInterval.rangePairLength = newInterval.rangePairs.length;
783+
rangePairLength = curRangeIndex;
768784
}
785+
return newInterval;
769786
}
770787

771-
// range iteration
772788
/**
773789
* Resets the range iteration to the beginning of the interval's ranges.
774790
*/
@@ -848,14 +864,15 @@ boolean isAtEnd() {
848864
}
849865
}
850866

851-
private boolean rangeIntersects(int rangeIndex, Interval other, int otherRangeIndex) {
852-
int start = Math.max(from(rangeIndex), other.from(otherRangeIndex));
853-
int end = Math.min(to(rangeIndex), other.to(otherRangeIndex));
854-
return start < end;
855-
}
856-
857867
/**
858-
* Checks if this interval intersects with a given interval using a binary search algorithm.
868+
* Checks if this interval intersects with a given interval using a binary search algorithm. The
869+
* method iterates through the ranges of the shorter interval and performs a binary search in
870+
* the ranges of the longer interval to check for intersections.
871+
* <p>
872+
* The method proceeds by directly iterating over the shorter interval and uses
873+
* {@link Arrays#binarySearch(int[], int)} to look for the current {@code from} in the longer
874+
* interval. If binarySearch finds the value in the long interval then there are two cases. If
875+
* the position of the value is even, then this is the from value which means
859876
*/
860877
public boolean binarySearchInterval(Interval currentInterval) {
861878
Interval longInterval;
@@ -876,40 +893,66 @@ public boolean binarySearchInterval(Interval currentInterval) {
876893
int shortTo = shortInterval.to(shortCurrentRangeIndex);
877894
int searchResult = Arrays.binarySearch(longArray, longCurrentRangeIndex, longInterval.rangePairLength, shortFrom);
878895
if (searchResult >= 0) {
879-
/*
880-
* The search found the other value. If it's even then the range was found because
881-
* short.from == long.from.
882-
*/
883896
if ((searchResult & 1) == 0) {
884-
assert shortInterval.rangeIntersects(shortCurrentRangeIndex, longInterval, searchResult);
897+
/*
898+
* The search found the other value. This means long contains either [shortFrom,
899+
* x) or [x, shortFrom). If it's even then the range was found because short
900+
* contains [shortFrom, x) and long contains [shortFrom, y).
901+
*/
885902
return true;
886903
}
887-
/*
888-
* short.from == long.to so short range doesn't intersect with current range in
889-
* long. Check the next range for overlap.
890-
*/
904+
// An odd searchResult means that shortFrom is the to of a range in long. In this
905+
// case the ranges are [shortFrom, shortTo) in short and [x, shortFrom) in long so
906+
// since the ranges are half open they don't intersect. Move to the next range in
907+
// long and fall through to check for overlap. This will check if the next range in
908+
// long begins before shortTo, which is the only way this short range could overlap.
909+
//
910+
// @formatter:off
911+
// short [shortFrom, shortTo)
912+
// long intersects [x, shortFrom) [nextLongFrom, y)
913+
// long doesn't intersect [x, shortFrom) [nextLongFrom, y)
914+
// @formatter:on
891915
longCurrentRangeIndex = searchResult + 1;
892916
} else {
917+
/*
918+
* If an element isn't found, binarySearch returns the proper insertion location as
919+
* (-(insertion point) - 1 so reverse this computation;
920+
*/
893921
int insertPoint = -(searchResult + 1);
894922
if ((insertPoint & 1) != 0) {
895-
/*
896-
* The insertion point is odd which means long.from is between short.from and
897-
* short.to so they directly intersect.
898-
*/
899-
assert shortInterval.rangeIntersects(shortCurrentRangeIndex, longInterval, insertPoint & ~1);
923+
// The insertion point is odd which means shortFrom > longFrom and shortFrom <
924+
// longTo which means they definitely intersect.
925+
//
926+
// @formatter:off
927+
// short [shortFrom, shortTo]
928+
// long intersects [x, y)
929+
// long intersects [x, y)
930+
// @formatter:on
900931
return true;
901932
}
933+
// The insertion point is even which means shortFrom is less than the longFrom, so
934+
// fall through and check if the current range in long begins before shortTo, which
935+
// is the only way this short range could overlap.
936+
//
937+
// @formatter:off
938+
// short [shortFrom, shortTo)
939+
// long intersects [nextLongFrom, y]
940+
// long doesn't intersect [nextLongFrom, y]
941+
// @formatter:on
902942
longCurrentRangeIndex = insertPoint;
903943
}
904944
if (longCurrentRangeIndex == longInterval.rangePairLength) {
905945
return false;
906946
}
907-
// Check if the next long range begins before the end of the short range.
947+
// Check if the long range begins before the end of the short range.
908948
int longFrom = longInterval.from(longCurrentRangeIndex);
909949
if (longFrom < shortTo) {
910-
assert shortInterval.rangeIntersects(shortCurrentRangeIndex, longInterval, longCurrentRangeIndex);
911950
return true;
912951
}
952+
/*
953+
* The current short range doesn't intersect with any range in long so move on to the
954+
* next.
955+
*/
913956
shortCurrentRangeIndex += 2;
914957
}
915958
return false;
@@ -920,7 +963,7 @@ public boolean binarySearchInterval(Interval currentInterval) {
920963
/**
921964
* Retrieves an element from an integer array using {@link Unsafe} for direct memory access. The
922965
* ranges checks add too much overhead and range check optimizations are unabled to eliminate
923-
* them so we rely on the correct properly checking iteration ranges.
966+
* them so we rely on the iteration logic to properly respect the bounds.
924967
*/
925968
private static int elementGet(int[] array, int index) {
926969
return UNSAFE.getInt(array, Unsafe.ARRAY_INT_BASE_OFFSET + (long) index * Unsafe.ARRAY_INT_INDEX_SCALE);
@@ -937,65 +980,72 @@ int currentIntersectsAt(Interval other) {
937980
return -1;
938981
}
939982

940-
return intersectsAt(this.currentRangeIndex, other, other.currentRangeIndex);
983+
return intersectsAt(this.currentRangeIndex, other, other.currentRangeIndex, Integer.MAX_VALUE);
941984
}
942985

943986
/**
944987
* Checks if this interval intersects with a given interval, starting from the first range.
945988
*/
946989
boolean intersects(Interval i) {
947-
return intersectsAt(0, i, 0) != -1;
990+
return intersectsAt(0, i, 0, Integer.MAX_VALUE) != -1;
948991
}
949992

950993
/**
951994
* Checks if this interval intersects with a given interval at a specified range iteration
952995
* position. If an intersection is found, it returns the position of the intersection. If no
953996
* intersection is found, it returns -1.
954997
*/
955-
private int intersectsAt(int thisCurrentRangeIndex, Interval other, int otherCurrentRangeIndex) {
998+
private int intersectsAt(int thisCurrentRangeIndex, Interval other, int otherCurrentRangeIndex, int limit) {
956999
int thisRangeIndex = thisCurrentRangeIndex;
9571000
int otherRangeIndex = otherCurrentRangeIndex;
9581001
int[] thisRangePairs = this.rangePairs;
9591002
int[] otherRangePairs = other.rangePairs;
1003+
int thisFrom = elementGet(thisRangePairs, thisRangeIndex);
1004+
int otherFrom = elementGet(otherRangePairs, otherRangeIndex);
9601005
do {
961-
int r1from = elementGet(thisRangePairs, thisRangeIndex);
962-
int r2from = elementGet(otherRangePairs, otherRangeIndex);
963-
int r1to = elementGet(thisRangePairs, thisRangeIndex + 1);
964-
if (r1from < r2from) {
965-
if (r1to <= r2from) {
1006+
assert thisFrom == elementGet(thisRangePairs, thisRangeIndex) : "mismatch";
1007+
assert otherFrom == elementGet(otherRangePairs, otherRangeIndex) : "mismatch";
1008+
1009+
if (thisFrom > limit && otherFrom > limit) {
1010+
return -1;
1011+
}
1012+
int thisTo = elementGet(thisRangePairs, thisRangeIndex + 1);
1013+
if (thisFrom < otherFrom) {
1014+
if (thisTo <= otherFrom) {
9661015
thisRangeIndex += 2;
9671016
if (thisRangeIndex == rangePairLength) {
9681017
return -1;
9691018
}
1019+
thisFrom = elementGet(thisRangePairs, thisRangeIndex);
9701020
} else {
971-
return r2from;
1021+
return otherFrom;
9721022
}
973-
} else {
974-
if (r2from < r1from) {
975-
if (elementGet(otherRangePairs, otherRangeIndex + 1) <= r1from) {
976-
otherRangeIndex += 2;
977-
if (otherRangeIndex == other.rangePairLength) {
978-
return -1;
979-
}
980-
} else {
981-
return r1from;
1023+
} else if (thisFrom > otherFrom) {
1024+
if (elementGet(otherRangePairs, otherRangeIndex + 1) <= thisFrom) {
1025+
otherRangeIndex += 2;
1026+
if (otherRangeIndex == other.rangePairLength) {
1027+
return -1;
9821028
}
983-
} else { // r1.from()() == r2.from()()
984-
if (r1from == r1to) {
985-
thisRangeIndex += 2;
986-
if (thisRangeIndex == rangePairLength) {
987-
return -1;
988-
}
989-
} else {
990-
if (r2from == elementGet(otherRangePairs, otherRangeIndex + 1)) {
991-
otherRangeIndex += 2;
992-
if (otherRangeIndex == other.rangePairLength) {
993-
return -1;
994-
}
995-
} else {
996-
return r1from;
997-
}
1029+
otherFrom = elementGet(otherRangePairs, otherRangeIndex);
1030+
} else {
1031+
return thisFrom;
1032+
}
1033+
} else if (thisFrom == thisTo) {
1034+
// thisFrom == otherFrom
1035+
thisRangeIndex += 2;
1036+
if (thisRangeIndex == rangePairLength) {
1037+
return -1;
1038+
}
1039+
thisFrom = elementGet(thisRangePairs, thisRangeIndex);
1040+
} else {
1041+
if (otherFrom == elementGet(otherRangePairs, otherRangeIndex + 1)) {
1042+
otherRangeIndex += 2;
1043+
if (otherRangeIndex == other.rangePairLength) {
1044+
return -1;
9981045
}
1046+
otherFrom = elementGet(otherRangePairs, otherRangeIndex);
1047+
} else {
1048+
return thisFrom;
9991049
}
10001050
}
10011051
} while (true); // TERMINATION ARGUMENT: guarded by the number of ranges reachable from this
@@ -1019,57 +1069,7 @@ int currentIntersectsAtLimit(Interval other, int limit) {
10191069
return -1;
10201070
}
10211071

1022-
int r1current = this.currentRangeIndex;
1023-
int r2current = other.currentRangeIndex;
1024-
int[] thisArray = this.rangePairs;
1025-
int[] otherArray = other.rangePairs;
1026-
do {
1027-
int r1from = elementGet(thisArray, r1current);
1028-
int r2from = elementGet(otherArray, r2current);
1029-
if (r1from > limit && r2from > limit) {
1030-
return -1;
1031-
}
1032-
1033-
int r1to = elementGet(thisArray, r1current + 1);
1034-
if (r1from < r2from) {
1035-
if (r1to <= r2from) {
1036-
r1current += 2;
1037-
if (r1current == rangePairLength) {
1038-
return -1;
1039-
}
1040-
} else {
1041-
return r2from;
1042-
}
1043-
} else {
1044-
if (r2from < r1from) {
1045-
if (elementGet(otherArray, r2current + 1) <= r1from) {
1046-
r2current += 2;
1047-
if (r2current == other.rangePairLength) {
1048-
return -1;
1049-
}
1050-
} else {
1051-
return r1from;
1052-
}
1053-
} else { // r1.from()() == r2.from()()
1054-
if (r1from == r1to) {
1055-
r1current += 2;
1056-
if (r1current == rangePairLength) {
1057-
return -1;
1058-
}
1059-
} else {
1060-
if (r2from == elementGet(otherArray, r2current + 1)) {
1061-
r2current += 2;
1062-
if (r2current == other.rangePairLength) {
1063-
return -1;
1064-
}
1065-
} else {
1066-
return r1from;
1067-
}
1068-
}
1069-
}
1070-
}
1071-
} while (true); // TERMINATION ARGUMENT: guarded by the number of ranges reachable from this
1072-
// and other
1072+
return intersectsAt(currentRangeIndex, other, other.currentRangeIndex, limit);
10731073
}
10741074

10751075
Interval(AllocatableValue operand, int operandNumber, Interval intervalEndMarker) {
@@ -1439,8 +1439,7 @@ Interval split(int splitPos, LinearScan allocator) {
14391439
assert LIRValueUtil.isVariable(operand) : "cannot split fixed intervals";
14401440

14411441
// allocate new interval
1442-
Interval result = newSplitChild(allocator);
1443-
result.split(this, splitPos);
1442+
Interval result = createSplit(splitPos, allocator);
14441443

14451444
// split list of use positions
14461445
result.usePosList = usePosList.splitAt(splitPos);

compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/alloc/lsra/LinearScan.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ public static class Options {
117117
// @formatter:off
118118
@Option(help = "Enable spill position optimization", type = OptionType.Debug)
119119
public static final OptionKey<Boolean> LIROptLSRAOptimizeSpillPosition = new NestedBooleanOptionKey(LIRPhase.Options.LIROptimization, true);
120-
@Option(help = "Use binary search interval longer than this limit", type = OptionType.Debug)
120+
@Option(help = "Use binary search if interval is longer than this limit", type = OptionType.Debug)
121121
public static final OptionKey<Integer> IntervalBinarySearchLimit = new OptionKey<>(100);
122122
// @formatter:on
123123
}

compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/alloc/lsra/LinearScanWalker.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,7 @@ void spillCollectInactiveAny(Interval current) {
300300
if (intervalBinarySearchLimit != -1 &&
301301
(interval.rangePairCount() > intervalBinarySearchLimit || current.rangePairCount() > intervalBinarySearchLimit)) {
302302
intersects = interval.binarySearchInterval(current);
303+
assert intersects == (interval.currentIntersectsAt(current) != -1) : intersects;
303304
} else {
304305
intersects = interval.currentIntersectsAt(current) != -1;
305306
}

0 commit comments

Comments
 (0)