@@ -66,6 +66,7 @@ class LinearScanWalker extends IntervalWalker {
66
66
private static final CountingTimerKey allocFreeRegister = countingTimer ("allocFreeRegister" );
67
67
private static final CountingTimerKey activateCurrent = countingTimer ("activateCurrent" );
68
68
private static final CountingTimerKey splitAndSpillIntersectingIntervals = countingTimer ("splitAndSpillIntersectingIntervals" );
69
+ private static final CountingTimerKey allocLockedRegister = countingTimer ("allocLockedRegister" );
69
70
70
71
/**
71
72
* The number of split operations on intervals generated by this walker. Splits are inserted
@@ -137,6 +138,11 @@ boolean isActiveRegister(Interval interval) {
137
138
return isActiveRegister (asRegister (interval .location ()).number );
138
139
}
139
140
141
+ /**
142
+ * Excludes a given interval from being used by setting its use position to 0 if it is assigned
143
+ * to an active register. This method is used to mark a register as blocked, indicating that it
144
+ * cannot be used for allocation.
145
+ */
140
146
void excludeFromUse (Interval i ) {
141
147
Value location = i .location ();
142
148
int i1 = asRegister (location ).number ;
@@ -146,31 +152,29 @@ void excludeFromUse(Interval i) {
146
152
}
147
153
148
154
void setUsePos (Interval interval , int intersects , boolean onlyProcessUsePos ) {
155
+ int i = asRegister (interval .location ()).number ;
156
+ assert isActiveRegister (i ) : "should have been check" ;
149
157
if (intersects != -1 ) {
150
158
assert intersects != 0 : "must use excludeFromUse to set usePos to 0" ;
151
- int i = asRegister (interval .location ()).number ;
152
- if (isActiveRegister (i )) {
153
- if (usePos [i ] > intersects ) {
154
- usePos [i ] = intersects ;
155
- }
156
- if (!onlyProcessUsePos ) {
157
- interval .spillNext = spillIntervals [i ];
158
- spillIntervals [i ] = interval ;
159
- }
159
+ if (usePos [i ] > intersects ) {
160
+ usePos [i ] = intersects ;
161
+ }
162
+ if (!onlyProcessUsePos ) {
163
+ interval .spillNext = spillIntervals [i ];
164
+ spillIntervals [i ] = interval ;
160
165
}
161
166
}
162
167
}
163
168
164
169
private void setUsePosAtIntersection (Interval interval , Interval current ) {
165
- if (isActiveRegister (interval )) {
166
- int i = asRegister (interval .location ()).number ;
167
- int savedUsePos = usePos [i ];
168
- int intersects = interval .currentIntersectsAtLimit (current , savedUsePos );
169
- if (intersects != -1 ) {
170
- assert intersects != 0 : "must use excludeFromUse to set usePos to 0" ;
171
- if (usePos [i ] > intersects ) {
172
- usePos [i ] = intersects ;
173
- }
170
+ assert isActiveRegister (interval ) : "called should have checked" ;
171
+ int i = asRegister (interval .location ()).number ;
172
+ int savedUsePos = usePos [i ];
173
+ int intersects = interval .currentIntersectsAtLimit (current , savedUsePos );
174
+ if (intersects != -1 ) {
175
+ assert intersects != 0 : "must use excludeFromUse to set usePos to 0" ;
176
+ if (usePos [i ] > intersects ) {
177
+ usePos [i ] = intersects ;
174
178
}
175
179
}
176
180
}
@@ -214,6 +218,12 @@ void freeExcludeActiveAny() {
214
218
}
215
219
}
216
220
221
+ /**
222
+ * Collects information about inactive intervals of type {@link RegisterBinding#Fixed} that
223
+ * intersect with the given {@code current} interval. The method iterates through the inactive
224
+ * intervals, checks if they are assigned to an active register, and updates the use position
225
+ * information accordingly.
226
+ */
217
227
@ SuppressWarnings ("try" )
218
228
void freeCollectInactiveFixed (Interval current ) {
219
229
try (DebugCloseable t = allocator .start (freeCollectInactiveFixed )) {
@@ -222,7 +232,7 @@ void freeCollectInactiveFixed(Interval current) {
222
232
if (isActiveRegister (interval )) {
223
233
int currentFrom = interval .currentFrom ();
224
234
if (current .to () <= currentFrom ) {
225
- assert !( interval .currentIntersectsAt (current ) != -1 ) : "must not intersect" ;
235
+ assert interval .currentIntersectsAt (current ) == -1 : "must not intersect" ;
226
236
int i = asRegister (interval .location ()).number ;
227
237
if (usePos [i ] > currentFrom ) {
228
238
usePos [i ] = currentFrom ;
@@ -236,19 +246,44 @@ void freeCollectInactiveFixed(Interval current) {
236
246
}
237
247
}
238
248
249
+ /**
250
+ * Collects information about inactive intervals of type {@link RegisterBinding#Any} that
251
+ * intersect with the given {@code current} interval. The method iterates through the inactive
252
+ * intervals, checks if they are assigned to an active register, and updates the use position
253
+ * information accordingly. The iteration stops when an interval is encountered whose
254
+ * {@linkplain Interval#currentFrom() current from} position exceeds the specified
255
+ * {@code limit}. This avoids potentially useless work that can become expensive for larger
256
+ * compiles.
257
+ */
239
258
@ SuppressWarnings ("try" )
240
- void freeCollectInactiveAny (Interval current ) {
259
+ void freeCollectInactiveAny (Interval current , int limit ) {
241
260
try (DebugCloseable t = allocator .start (freeCollectInactiveAny )) {
242
261
Interval interval = inactiveLists .get (RegisterBinding .Any );
243
262
while (!interval .isEndMarker ()) {
244
263
if (isActiveRegister (interval )) {
245
264
setUsePosAtIntersection (interval , current );
246
265
}
266
+ if (interval .currentFrom () > limit ) {
267
+ /*
268
+ * All following intervals must be greater than limit as activeLists and
269
+ * inactiveLists are sorted by currentFrom. See
270
+ * #addToListSortedByCurrentFromPositions.
271
+ */
272
+ return ;
273
+ }
247
274
interval = interval .next ;
248
275
}
249
276
}
250
277
}
251
278
279
+ /**
280
+ * Excludes all {@linkplain RegisterBinding#Fixed fixed} intervals currently
281
+ * {@linkplain State#Active active} from being used. This is done by iterating over the
282
+ * {@linkplain #activeLists active} intervals with a {@linkplain RegisterBinding#Fixed fixed}
283
+ * binding and calling {@link #excludeFromUse(Interval)} on each one.
284
+ *
285
+ * @see #excludeFromUse(Interval)
286
+ */
252
287
@ SuppressWarnings ("try" )
253
288
void spillExcludeActiveFixed () {
254
289
try (DebugCloseable t = allocator .start (spillExcludeActiveFixed )) {
@@ -268,7 +303,7 @@ void spillBlockInactiveFixed(Interval current) {
268
303
if (current .to () > interval .currentFrom ()) {
269
304
setBlockPos (interval , current );
270
305
} else {
271
- assert !( interval .currentIntersectsAt (current ) != -1 ) : "invalid optimization: intervals intersect" ;
306
+ assert interval .currentIntersectsAt (current ) == -1 : "invalid optimization: intervals intersect" ;
272
307
}
273
308
274
309
interval = interval .next ;
@@ -801,18 +836,41 @@ boolean allocFreeRegister(Interval interval) {
801
836
DebugContext debug = allocator .getDebug ();
802
837
try (Indent indent = debug .logAndIndent ("trying to find free register for %s" , interval ); DebugCloseable t = allocator .start (allocFreeRegister )) {
803
838
839
+ /*
840
+ * When allocating a partial register, we want it to be free at least until this
841
+ * position. If the interval has already been split, we add 2 as a heuristic to only
842
+ * consider registers free for at least two instructions. This is meant to avoid
843
+ * shuffling data between registers after every single instruction. If register pressure
844
+ * is so high that we would only get a partial register for the duration of one
845
+ * instruction and then have to split again, prefer not choosing such a register at all.
846
+ * We will spill instead.
847
+ */
848
+ int partialRegRequestedUntil = interval .from () + 1 + (interval .isSplitChild () ? 2 : 0 );
849
+ int intervalTo = interval .to ();
850
+
804
851
initUseLists (true );
852
+ /* Mark the active registers as busy */
805
853
freeExcludeActiveFixed ();
806
854
freeExcludeActiveAny ();
855
+ /*
856
+ * Compute the earliest use position of inactive intervals that intersect with this
857
+ * interval. These are intervals that might become active in the future.
858
+ */
807
859
freeCollectInactiveFixed (interval );
808
- freeCollectInactiveAny (interval );
809
- // freeCollectUnhandled(fixedKind, cur);
860
+ /*
861
+ * The inactive any list can in some cases be very long which can make this step
862
+ * expensive, so pass in the minimum usePos required to satisfy this interval.
863
+ */
864
+ freeCollectInactiveAny (interval , Math .max (partialRegRequestedUntil , intervalTo ));
865
+
810
866
assert unhandledLists .get (RegisterBinding .Fixed ).isEndMarker () : "must not have unhandled fixed intervals because all fixed intervals have a use at position 0" ;
811
867
812
- // usePos contains the start of the next interval that has this register assigned
813
- // (either as a fixed register or a normal allocated register in the past)
814
- // only intervals overlapping with cur are processed, non-overlapping invervals can be
815
- // ignored safely
868
+ /*
869
+ * usePos contains the start of the next interval that has this register assigned
870
+ * (either as a fixed register or a normal allocated register in the past) only
871
+ * intervals overlapping with cur are processed, non-overlapping invervals can be
872
+ * ignored safely
873
+ */
816
874
if (debug .isLogEnabled ()) {
817
875
// Enable this logging to see all register states
818
876
try (Indent indent2 = debug .logAndIndent ("state of registers:" )) {
@@ -833,18 +891,6 @@ boolean allocFreeRegister(Interval interval) {
833
891
}
834
892
assert interval .location () == null : "register already assigned to interval" ;
835
893
836
- /*
837
- * When allocating a partial register, we want it to be free at least until this
838
- * position. If the interval has already been split, we add 2 as a heuristic to only
839
- * consider registers free for at least two instructions. This is meant to avoid
840
- * shuffling data between registers after every single instruction. If register pressure
841
- * is so high that we would only get a partial register for the duration of one
842
- * instruction and then have to split again, prefer not choosing such a register at all.
843
- * We will spill instead.
844
- */
845
- int partialRegRequestedUntil = interval .from () + 1 + (interval .isSplitChild () ? 2 : 0 );
846
- int intervalTo = interval .to ();
847
-
848
894
boolean needSplit = false ;
849
895
int splitPos = -1 ;
850
896
@@ -907,7 +953,8 @@ void splitAndSpillIntersectingIntervals(Register reg) {
907
953
@ SuppressWarnings ("try" )
908
954
void allocLockedRegister (Interval interval ) {
909
955
DebugContext debug = allocator .getDebug ();
910
- try (Indent indent = debug .logAndIndent ("alloc locked register: need to split and spill to get register for %s" , interval )) {
956
+ try (Indent indent = debug .logAndIndent ("alloc locked register: need to split and spill to get register for %s" , interval );
957
+ DebugCloseable t = allocator .start (allocLockedRegister )) {
911
958
912
959
// the register must be free at least until this position
913
960
int firstUsage = interval .firstUsage (RegisterPriority .MustHaveRegister );
0 commit comments