comparison graal/Compiler/src/com/sun/c1x/alloc/Interval.java @ 2507:9ec15d6914ca

Pull over of compiler from maxine repository.
author Thomas Wuerthinger <thomas@wuerthinger.net>
date Wed, 27 Apr 2011 11:43:22 +0200
parents
children
comparison
equal deleted inserted replaced
2506:4a3bf8a5bf41 2507:9ec15d6914ca
1 /*
2 * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23 package com.sun.c1x.alloc;
24
25 import java.util.*;
26
27 import com.sun.c1x.*;
28 import com.sun.c1x.debug.*;
29 import com.sun.c1x.lir.*;
30 import com.sun.c1x.util.*;
31 import com.sun.cri.ci.*;
32
33 /**
34 * Represents an interval in the {@linkplain LinearScan linear scan register allocator}.
35 *
36 * @author Thomas Wuerthinger
37 * @author Doug Simon
38 */
39 public final class Interval {
40
41 /**
42 * A pair of intervals.
43 */
44 static final class Pair {
45 public final Interval first;
46 public final Interval second;
47 public Pair(Interval first, Interval second) {
48 this.first = first;
49 this.second = second;
50 }
51 }
52
53 /**
54 * A set of interval lists, one per {@linkplain RegisterBinding binding} type.
55 */
56 static final class RegisterBindingLists {
57
58 /**
59 * List of intervals whose binding is currently {@link RegisterBinding#Fixed}.
60 */
61 public Interval fixed;
62
63 /**
64 * List of intervals whose binding is currently {@link RegisterBinding#Any}.
65 */
66 public Interval any;
67
68 public RegisterBindingLists(Interval fixed, Interval any) {
69 this.fixed = fixed;
70 this.any = any;
71 }
72
73 /**
74 * Gets the list for a specified binding.
75 *
76 * @param binding specifies the list to be returned
77 * @return the list of intervals whose binding is {@code binding}
78 */
79 public Interval get(RegisterBinding binding) {
80 if (binding == RegisterBinding.Any) {
81 return any;
82 }
83 assert binding == RegisterBinding.Fixed;
84 return fixed;
85 }
86
87 /**
88 * Sets the list for a specified binding.
89 *
90 * @param binding specifies the list to be replaced
91 * @param a list of intervals whose binding is {@code binding}
92 */
93 public void set(RegisterBinding binding, Interval list) {
94 assert list != null;
95 if (binding == RegisterBinding.Any) {
96 any = list;
97 } else {
98 assert binding == RegisterBinding.Fixed;
99 fixed = list;
100 }
101 }
102
103 /**
104 * Adds an interval to a list sorted by {@linkplain Interval#currentFrom() current from} positions.
105 *
106 * @param binding specifies the list to be updated
107 * @param interval the interval to add
108 */
109 public void addToListSortedByCurrentFromPositions(RegisterBinding binding, Interval interval) {
110 Interval list = get(binding);
111 Interval prev = null;
112 Interval cur = list;
113 while (cur.currentFrom() < interval.currentFrom()) {
114 prev = cur;
115 cur = cur.next;
116 }
117 Interval result = list;
118 if (prev == null) {
119 // add to head of list
120 result = interval;
121 } else {
122 // add before 'cur'
123 prev.next = interval;
124 }
125 interval.next = cur;
126 set(binding, result);
127 }
128
129 /**
130 * Adds an interval to a list sorted by {@linkplain Interval#from() start} positions and
131 * {@linkplain Interval#firstUsage(RegisterPriority) first usage} positions.
132 *
133 * @param binding specifies the list to be updated
134 * @param interval the interval to add
135 */
136 public void addToListSortedByStartAndUsePositions(RegisterBinding binding, Interval interval) {
137 Interval list = get(binding);
138 Interval prev = null;
139 Interval cur = list;
140 while (cur.from() < interval.from() || (cur.from() == interval.from() && cur.firstUsage(RegisterPriority.None) < interval.firstUsage(RegisterPriority.None))) {
141 prev = cur;
142 cur = cur.next;
143 }
144 if (prev == null) {
145 list = interval;
146 } else {
147 prev.next = interval;
148 }
149 interval.next = cur;
150 set(binding, list);
151 }
152
153 /**
154 * Removes an interval from a list.
155 *
156 * @param binding specifies the list to be updated
157 * @param interval the interval to remove
158 */
159 public void remove(RegisterBinding binding, Interval i) {
160 Interval list = get(binding);
161 Interval prev = null;
162 Interval cur = list;
163 while (cur != i) {
164 assert cur != null && cur != Interval.EndMarker : "interval has not been found in list: " + i;
165 prev = cur;
166 cur = cur.next;
167 }
168 if (prev == null) {
169 set(binding, cur.next);
170 } else {
171 prev.next = cur.next;
172 }
173 }
174 }
175
176 /**
177 * Constants denoting the register usage priority for an interval.
178 * The constants are declared in increasing order of priority are
179 * are used to optimize spilling when multiple overlapping intervals
180 * compete for limited registers.
181 */
182 enum RegisterPriority {
183 /**
184 * No special reason for an interval to be allocated a register.
185 */
186 None,
187
188 /**
189 * Priority level for intervals live at the end of a loop.
190 */
191 LiveAtLoopEnd,
192
193 /**
194 * Priority level for intervals that should be allocated to a register.
195 */
196 ShouldHaveRegister,
197
198 /**
199 * Priority level for intervals that must be allocated to a register.
200 */
201 MustHaveRegister;
202
203 public static final RegisterPriority[] VALUES = values();
204
205 /**
206 * Determines if this priority is higher than or equal to a given priority.
207 */
208 public boolean greaterEqual(RegisterPriority other) {
209 return ordinal() >= other.ordinal();
210 }
211
212 /**
213 * Determines if this priority is lower than a given priority.
214 */
215 public boolean lessThan(RegisterPriority other) {
216 return ordinal() < other.ordinal();
217 }
218 }
219
220 /**
221 * Constants denoting whether an interval is bound to a specific register. This models
222 * platform dependencies on register usage for certain instructions.
223 */
224 enum RegisterBinding {
225 /**
226 * Interval is bound to a specific register as required by the platform.
227 */
228 Fixed,
229
230 /**
231 * Interval has no specific register requirements.
232 */
233 Any;
234
235 public static final RegisterBinding[] VALUES = values();
236 }
237
238 /**
239 * Constants denoting the linear-scan states an interval may be in with respect to the
240 * {@linkplain Interval#from() start} {@code position} of the interval being processed.
241 */
242 enum State {
243 /**
244 * An interval that starts after {@code position}.
245 */
246 Unhandled,
247
248 /**
249 * An interval that {@linkplain Interval#covers covers} {@code position} and has an assigned register.
250 */
251 Active,
252
253 /**
254 * An interval that starts before and ends after {@code position} but does not
255 * {@linkplain Interval#covers cover} it due to a lifetime hole.
256 */
257 Inactive,
258
259 /**
260 * An interval that ends before {@code position} or is spilled to memory.
261 */
262 Handled;
263 }
264
265 /**
266 * Constants used in optimization of spilling of an interval.
267 */
268 enum SpillState {
269 /**
270 * Starting state of calculation: no definition found yet.
271 */
272 NoDefinitionFound,
273
274 /**
275 * One definition has already been found. Two consecutive definitions are treated as one
276 * (e.g. a consecutive move and add because of two-operand LIR form).
277 * The position of this definition is given by {@link Interval#spillDefinitionPos()}.
278 */
279 NoSpillStore,
280
281 /**
282 * One spill move has already been inserted.
283 */
284 OneSpillStore,
285
286 /**
287 * The interval should be stored immediately after its definition to prevent
288 * multiple redundant stores.
289 */
290 StoreAtDefinition,
291
292 /**
293 * The interval starts in memory (e.g. method parameter), so a store is never necessary.
294 */
295 StartInMemory,
296
297 /**
298 * The interval has more than one definition (e.g. resulting from phi moves), so stores
299 * to memory are not optimized.
300 */
301 NoOptimization
302 }
303
304 /**
305 * List of use positions. Each entry in the list records the use position and register
306 * priority associated with the use position. The entries in the list are in descending
307 * order of use position.
308 *
309 * @author Doug Simon
310 */
311 public static final class UsePosList {
312 private IntList list;
313
314 /**
315 * Creates a use list.
316 *
317 * @param initialCapacity the initial capacity of the list in terms of entries
318 */
319 public UsePosList(int initialCapacity) {
320 list = new IntList(initialCapacity * 2);
321 }
322
323 private UsePosList(IntList list) {
324 this.list = list;
325 }
326
327 /**
328 * Splits this list around a given position. All entries in this list with a use position greater or equal than
329 * {@code splitPos} are removed from this list and added to the returned list.
330 *
331 * @param splitPos the position for the split
332 * @return a use position list containing all entries removed from this list that have a use position greater or equal
333 * than {@code splitPos}
334 */
335 public UsePosList splitAt(int splitPos) {
336 int i = size() - 1;
337 int len = 0;
338 while (i >= 0 && usePos(i) < splitPos) {
339 --i;
340 len += 2;
341 }
342 int listSplitIndex = (i + 1) * 2;
343 IntList childList = list;
344 list = IntList.copy(this.list, listSplitIndex, len);
345 childList.setSize(listSplitIndex);
346 UsePosList child = new UsePosList(childList);
347 return child;
348 }
349
350 /**
351 * Gets the use position at a specified index in this list.
352 *
353 * @param index the index of the entry for which the use position is returned
354 * @return the use position of entry {@code index} in this list
355 */
356 public int usePos(int index) {
357 return list.get(index << 1);
358 }
359
360 /**
361 * Gets the register priority for the use position at a specified index in this list.
362 *
363 * @param index the index of the entry for which the register priority is returned
364 * @return the register priority of entry {@code index} in this list
365 */
366 public RegisterPriority registerPriority(int index) {
367 return RegisterPriority.VALUES[list.get((index << 1) + 1)];
368 }
369
370 public void add(int usePos, RegisterPriority registerPriority) {
371 assert list.size() == 0 || usePos(size() - 1) > usePos;
372 list.add(usePos);
373 list.add(registerPriority.ordinal());
374 }
375
376 public int size() {
377 return list.size() >> 1;
378 }
379
380 public void removeLowestUsePos() {
381 list.setSize(list.size() - 2);
382 }
383
384 public void setRegisterPriority(int index, RegisterPriority registerPriority) {
385 list.set(index * 2, registerPriority.ordinal());
386 }
387
388 @Override
389 public String toString() {
390 StringBuilder buf = new StringBuilder("[");
391 for (int i = size() - 1; i >= 0; --i) {
392 if (buf.length() != 1) {
393 buf.append(", ");
394 }
395 RegisterPriority prio = registerPriority(i);
396 buf.append(usePos(i)).append(" -> ").append(prio.ordinal()).append(':').append(prio);
397 }
398 return buf.append("]").toString();
399 }
400 }
401
402 /**
403 * The {@linkplain CiRegisterValue register} or {@linkplain CiVariable variable} for this interval prior to register allocation.
404 */
405 public final CiValue operand;
406
407 /**
408 * The {@linkplain OperandPool#operandNumber(CiValue) operand number} for this interval's {@linkplain #operand operand}.
409 */
410 public final int operandNumber;
411
412 /**
413 * The {@linkplain CiRegisterValue register}, {@linkplain CiStackSlot spill slot} or {@linkplain CiAddress address} assigned to this interval.
414 */
415 private CiValue location;
416
417 /**
418 * The stack slot to which all splits of this interval are spilled if necessary.
419 */
420 private CiStackSlot spillSlot;
421
422 /**
423 * The kind of this interval.
424 * Only valid if this is a {@linkplain #isVariable() variable}.
425 */
426 private CiKind kind;
427
428 /**
429 * The head of the list of ranges describing this interval. This list is sorted by {@linkplain LIRInstruction#id instruction ids}.
430 */
431 private Range first;
432
433 /**
434 * List of (use-positions, register-priorities) pairs, sorted by use-positions.
435 */
436 private UsePosList usePosList;
437
438 /**
439 * Iterator used to traverse the ranges of an interval.
440 */
441 private Range current;
442
443 /**
444 * Link to next interval in a sorted list of intervals that ends with {@link #EndMarker}.
445 */
446 Interval next;
447
448 /**
449 * The linear-scan state of this interval.
450 */
451 State state;
452
453 private int cachedTo; // cached value: to of last range (-1: not cached)
454
455 /**
456 * The interval from which this one is derived. If this is a {@linkplain #isSplitParent() split parent}, it points to itself.
457 */
458 private Interval splitParent;
459
460 /**
461 * List of all intervals that are split off from this interval. This is only used if this is a {@linkplain #isSplitParent() split parent}.
462 */
463 private List<Interval> splitChildren = Collections.emptyList();
464
465 /**
466 * Current split child that has been active or inactive last (always stored in split parents).
467 */
468 private Interval currentSplitChild;
469
470 /**
471 * Specifies if move is inserted between currentSplitChild and this interval when interval gets active the first time.
472 */
473 private boolean insertMoveWhenActivated;
474
475 /**
476 * For spill move optimization.
477 */
478 private SpillState spillState;
479
480 /**
481 * Position where this interval is defined (if defined only once).
482 */
483 private int spillDefinitionPos;
484
485 /**
486 * This interval should be assigned the same location as the hint interval.
487 */
488 private Interval locationHint;
489
490 void assignLocation(CiValue location) {
491 if (location.isRegister()) {
492 assert this.location == null : "cannot re-assign location for " + this;
493 if (location.kind == CiKind.Illegal && kind != CiKind.Illegal) {
494 location = location.asRegister().asValue(kind);
495 }
496 } else {
497 assert this.location == null || this.location.isRegister() : "cannot re-assign location for " + this;
498 assert location.isStackSlot();
499 assert location.kind != CiKind.Illegal;
500 assert location.kind == this.kind;
501 }
502 this.location = location;
503 }
504
505 /**
506 * Gets the {@linkplain CiRegisterValue register}, {@linkplain CiStackSlot spill slot} or {@linkplain CiAddress address} assigned to this interval.
507 */
508 public CiValue location() {
509 return location;
510 }
511
512 public CiKind kind() {
513 assert !operand.isRegister() : "cannot access type for fixed interval";
514 return kind;
515 }
516
517 void setKind(CiKind kind) {
518 assert operand.isRegister() || this.kind == CiKind.Illegal || this.kind == kind : "overwriting existing type";
519 assert kind == kind.stackKind() || kind == CiKind.Short : "these kinds should have int type registers";
520 this.kind = kind;
521 }
522
523 public Range first() {
524 return first;
525 }
526
527 int from() {
528 return first.from;
529 }
530
531 int to() {
532 if (cachedTo == -1) {
533 cachedTo = calcTo();
534 }
535 assert cachedTo == calcTo() : "invalid cached value";
536 return cachedTo;
537 }
538
539 int numUsePositions() {
540 return usePosList.size();
541 }
542
543 void setLocationHint(Interval interval) {
544 locationHint = interval;
545 }
546
547 boolean isSplitParent() {
548 return splitParent == this;
549 }
550
551 boolean isSplitChild() {
552 return splitParent != this;
553 }
554
555 /**
556 * Gets the split parent for this interval.
557 */
558 public Interval splitParent() {
559 assert splitParent.isSplitParent() : "not a split parent: " + this;
560 return splitParent;
561 }
562
563 /**
564 * Gets the canonical spill slot for this interval.
565 */
566 CiStackSlot spillSlot() {
567 return splitParent().spillSlot;
568 }
569
570 void setSpillSlot(CiStackSlot slot) {
571 assert splitParent().spillSlot == null : "connot overwrite existing spill slot";
572 splitParent().spillSlot = slot;
573 }
574
575 Interval currentSplitChild() {
576 return splitParent().currentSplitChild;
577 }
578
579 void makeCurrentSplitChild() {
580 splitParent().currentSplitChild = this;
581 }
582
583 boolean insertMoveWhenActivated() {
584 return insertMoveWhenActivated;
585 }
586
587 void setInsertMoveWhenActivated(boolean b) {
588 insertMoveWhenActivated = b;
589 }
590
591 // for spill optimization
592 public SpillState spillState() {
593 return splitParent().spillState;
594 }
595
596 int spillDefinitionPos() {
597 return splitParent().spillDefinitionPos;
598 }
599
600 void setSpillState(SpillState state) {
601 assert state.ordinal() >= spillState().ordinal() : "state cannot decrease";
602 splitParent().spillState = state;
603 }
604
605 void setSpillDefinitionPos(int pos) {
606 assert spillDefinitionPos() == -1 : "cannot set the position twice";
607 splitParent().spillDefinitionPos = pos;
608 }
609
610 // returns true if this interval has a shadow copy on the stack that is always correct
611 boolean alwaysInMemory() {
612 return splitParent().spillState == SpillState.StoreAtDefinition || splitParent().spillState == SpillState.StartInMemory;
613 }
614
615 void removeFirstUsePos() {
616 usePosList.removeLowestUsePos();
617 }
618
619 // test intersection
620 boolean intersects(Interval i) {
621 return first.intersects(i.first);
622 }
623
624 int intersectsAt(Interval i) {
625 return first.intersectsAt(i.first);
626 }
627
628 // range iteration
629 void rewindRange() {
630 current = first;
631 }
632
633 void nextRange() {
634 assert this != EndMarker : "not allowed on sentinel";
635 current = current.next;
636 }
637
638 int currentFrom() {
639 return current.from;
640 }
641
642 int currentTo() {
643 return current.to;
644 }
645
646 boolean currentAtEnd() {
647 return current == Range.EndMarker;
648 }
649
650 boolean currentIntersects(Interval it) {
651 return current.intersects(it.current);
652 }
653
654 int currentIntersectsAt(Interval it) {
655 return current.intersectsAt(it.current);
656 }
657
658 /**
659 * Sentinel interval to denote the end of an interval list.
660 */
661 static final Interval EndMarker = new Interval(CiValue.IllegalValue, -1);
662
663 Interval(CiValue operand, int operandNumber) {
664 C1XMetrics.LSRAIntervalsCreated++;
665 assert operand != null;
666 this.operand = operand;
667 this.operandNumber = operandNumber;
668 if (operand.isRegister()) {
669 location = operand;
670 } else {
671 assert operand.isIllegal() || operand.isVariable();
672 }
673 this.kind = CiKind.Illegal;
674 this.first = Range.EndMarker;
675 this.usePosList = new UsePosList(4);
676 this.current = Range.EndMarker;
677 this.next = EndMarker;
678 this.cachedTo = -1;
679 this.spillState = SpillState.NoDefinitionFound;
680 this.spillDefinitionPos = -1;
681 splitParent = this;
682 currentSplitChild = this;
683 }
684
685 int calcTo() {
686 assert first != Range.EndMarker : "interval has no range";
687
688 Range r = first;
689 while (r.next != Range.EndMarker) {
690 r = r.next;
691 }
692 return r.to;
693 }
694
695 // consistency check of split-children
696 boolean checkSplitChildren() {
697 if (!splitChildren.isEmpty()) {
698 assert isSplitParent() : "only split parents can have children";
699
700 for (int i = 0; i < splitChildren.size(); i++) {
701 Interval i1 = splitChildren.get(i);
702
703 assert i1.splitParent() == this : "not a split child of this interval";
704 assert i1.kind() == kind() : "must be equal for all split children";
705 assert i1.spillSlot() == spillSlot() : "must be equal for all split children";
706
707 for (int j = i + 1; j < splitChildren.size(); j++) {
708 Interval i2 = splitChildren.get(j);
709
710 assert i1.operand != i2.operand : "same register number";
711
712 if (i1.from() < i2.from()) {
713 assert i1.to() <= i2.from() && i1.to() < i2.to() : "intervals overlapping";
714 } else {
715 assert i2.from() < i1.from() : "intervals start at same opId";
716 assert i2.to() <= i1.from() && i2.to() < i1.to() : "intervals overlapping";
717 }
718 }
719 }
720 }
721
722 return true;
723 }
724
725 public Interval locationHint(boolean searchSplitChild, LinearScan allocator) {
726 if (!searchSplitChild) {
727 return locationHint;
728 }
729
730 if (locationHint != null) {
731 assert locationHint.isSplitParent() : "ony split parents are valid hint registers";
732
733 if (locationHint.location != null && locationHint.location.isRegister()) {
734 return locationHint;
735 } else if (!locationHint.splitChildren.isEmpty()) {
736 // search the first split child that has a register assigned
737 int len = locationHint.splitChildren.size();
738 for (int i = 0; i < len; i++) {
739 Interval interval = locationHint.splitChildren.get(i);
740 if (interval.location != null && interval.location.isRegister()) {
741 return interval;
742 }
743 }
744 }
745 }
746
747 // no hint interval found that has a register assigned
748 return null;
749 }
750
751 Interval getSplitChildAtOpId(int opId, LIRInstruction.OperandMode mode, LinearScan allocator) {
752 assert isSplitParent() : "can only be called for split parents";
753 assert opId >= 0 : "invalid opId (method cannot be called for spill moves)";
754
755 if (splitChildren.isEmpty()) {
756 assert this.covers(opId, mode) : this + " does not cover " + opId;
757 return this;
758 } else {
759 Interval result = null;
760 int len = splitChildren.size();
761
762 // in outputMode, the end of the interval (opId == cur.to()) is not valid
763 int toOffset = (mode == LIRInstruction.OperandMode.Output ? 0 : 1);
764
765 int i;
766 for (i = 0; i < len; i++) {
767 Interval cur = splitChildren.get(i);
768 if (cur.from() <= opId && opId < cur.to() + toOffset) {
769 if (i > 0) {
770 // exchange current split child to start of list (faster access for next call)
771 Util.atPutGrow(splitChildren, i, splitChildren.get(0), null);
772 Util.atPutGrow(splitChildren, 0, cur, null);
773 }
774
775 // interval found
776 result = cur;
777 break;
778 }
779 }
780
781 assert checkSplitChild(result, opId, allocator, toOffset, mode);
782 return result;
783 }
784 }
785
786 private boolean checkSplitChild(Interval result, int opId, LinearScan allocator, int toOffset, LIRInstruction.OperandMode mode) {
787 if (result == null) {
788 // this is an error
789 StringBuilder msg = new StringBuilder(this.toString()).append(" has no child at ").append(opId);
790 if (!splitChildren.isEmpty()) {
791 Interval first = splitChildren.get(0);
792 Interval last = splitChildren.get(splitChildren.size() - 1);
793 msg.append(" (first = ").append(first).append(", last = ").append(last).append(")");
794 }
795 throw new CiBailout("Linear Scan Error: " + msg);
796 }
797
798 if (!splitChildren.isEmpty()) {
799 for (Interval interval : splitChildren) {
800 if (interval != result && interval.from() <= opId && opId < interval.to() + toOffset) {
801 TTY.println(String.format("two valid result intervals found for opId %d: %d and %d", opId, result.operandNumber, interval.operandNumber));
802 TTY.println(result.logString(allocator));
803 TTY.println(interval.logString(allocator));
804 throw new CiBailout("two valid result intervals found");
805 }
806 }
807 }
808 assert result.covers(opId, mode) : "opId not covered by interval";
809 return true;
810 }
811
812 // returns the last split child that ends before the given opId
813 Interval getSplitChildBeforeOpId(int opId) {
814 assert opId >= 0 : "invalid opId";
815
816 Interval parent = splitParent();
817 Interval result = null;
818
819 assert !parent.splitChildren.isEmpty() : "no split children available";
820 int len = parent.splitChildren.size();
821
822 for (int i = len - 1; i >= 0; i--) {
823 Interval cur = parent.splitChildren.get(i);
824 if (cur.to() <= opId && (result == null || result.to() < cur.to())) {
825 result = cur;
826 }
827 }
828
829 assert result != null : "no split child found";
830 return result;
831 }
832
833 // checks if opId is covered by any split child
834 boolean splitChildCovers(int opId, LIRInstruction.OperandMode mode) {
835 assert isSplitParent() : "can only be called for split parents";
836 assert opId >= 0 : "invalid opId (method can not be called for spill moves)";
837
838 if (splitChildren.isEmpty()) {
839 // simple case if interval was not split
840 return covers(opId, mode);
841
842 } else {
843 // extended case: check all split children
844 int len = splitChildren.size();
845 for (int i = 0; i < len; i++) {
846 Interval cur = splitChildren.get(i);
847 if (cur.covers(opId, mode)) {
848 return true;
849 }
850 }
851 return false;
852 }
853 }
854
855 // Note: use positions are sorted descending . first use has highest index
856 int firstUsage(RegisterPriority minRegisterPriority) {
857 assert operand.isVariable() : "cannot access use positions for fixed intervals";
858
859 for (int i = usePosList.size() - 1; i >= 0; --i) {
860 RegisterPriority registerPriority = usePosList.registerPriority(i);
861 if (registerPriority.greaterEqual(minRegisterPriority)) {
862 return usePosList.usePos(i);
863 }
864 }
865 return Integer.MAX_VALUE;
866 }
867
868 int nextUsage(RegisterPriority minRegisterPriority, int from) {
869 assert operand.isVariable() : "cannot access use positions for fixed intervals";
870
871 for (int i = usePosList.size() - 1; i >= 0; --i) {
872 int usePos = usePosList.usePos(i);
873 if (usePos >= from && usePosList.registerPriority(i).greaterEqual(minRegisterPriority)) {
874 return usePos;
875 }
876 }
877 return Integer.MAX_VALUE;
878 }
879
880 int nextUsageExact(RegisterPriority exactRegisterPriority, int from) {
881 assert operand.isVariable() : "cannot access use positions for fixed intervals";
882
883 for (int i = usePosList.size() - 1; i >= 0; --i) {
884 int usePos = usePosList.usePos(i);
885 if (usePos >= from && usePosList.registerPriority(i) == exactRegisterPriority) {
886 return usePos;
887 }
888 }
889 return Integer.MAX_VALUE;
890 }
891
892 int previousUsage(RegisterPriority minRegisterPriority, int from) {
893 assert operand.isVariable() : "cannot access use positions for fixed intervals";
894
895 int prev = 0;
896 for (int i = usePosList.size() - 1; i >= 0; --i) {
897 int usePos = usePosList.usePos(i);
898 if (usePos > from) {
899 return prev;
900 }
901 if (usePosList.registerPriority(i).greaterEqual(minRegisterPriority)) {
902 prev = usePos;
903 }
904 }
905 return prev;
906 }
907
908 void addUsePos(int pos, RegisterPriority registerPriority) {
909 assert covers(pos, LIRInstruction.OperandMode.Input) : "use position not covered by live range";
910
911 // do not add use positions for precolored intervals because they are never used
912 if (registerPriority != RegisterPriority.None && operand.isVariable()) {
913 if (C1XOptions.DetailedAsserts) {
914 for (int i = 0; i < usePosList.size(); i++) {
915 assert pos <= usePosList.usePos(i) : "already added a use-position with lower position";
916 if (i > 0) {
917 assert usePosList.usePos(i) < usePosList.usePos(i - 1) : "not sorted descending";
918 }
919 }
920 }
921
922 // Note: addUse is called in descending order, so list gets sorted
923 // automatically by just appending new use positions
924 int len = usePosList.size();
925 if (len == 0 || usePosList.usePos(len - 1) > pos) {
926 usePosList.add(pos, registerPriority);
927 } else if (usePosList.registerPriority(len - 1).lessThan(registerPriority)) {
928 assert usePosList.usePos(len - 1) == pos : "list not sorted correctly";
929 usePosList.setRegisterPriority(len - 1, registerPriority);
930 }
931 }
932 }
933
934 void addRange(int from, int to) {
935 assert from < to : "invalid range";
936 assert first() == Range.EndMarker || to < first().next.from : "not inserting at begin of interval";
937 assert from <= first().to : "not inserting at begin of interval";
938
939 if (first.from <= to) {
940 assert first != Range.EndMarker;
941 // join intersecting ranges
942 first.from = Math.min(from, first().from);
943 first.to = Math.max(to, first().to);
944 } else {
945 // insert new range
946 first = new Range(from, to, first());
947 }
948 }
949
950 Interval newSplitChild(LinearScan allocator) {
951 // allocate new interval
952 Interval parent = splitParent();
953 Interval result = allocator.createDerivedInterval(parent);
954 result.setKind(kind());
955
956 result.splitParent = parent;
957 result.setLocationHint(parent);
958
959 // insert new interval in children-list of parent
960 if (parent.splitChildren.isEmpty()) {
961 assert isSplitParent() : "list must be initialized at first split";
962
963 // Create new non-shared list
964 parent.splitChildren = new ArrayList<Interval>(4);
965 parent.splitChildren.add(this);
966 }
967 parent.splitChildren.add(result);
968
969 return result;
970 }
971
972 /**
973 * Splits this interval at a specified position and returns the remainder as a new <i>child</i> interval
974 * of this interval's {@linkplain #splitParent() parent} interval.
975 * <p>
976 * When an interval is split, a bi-directional link is established between the original <i>parent</i>
977 * interval and the <i>children</i> intervals that are split off this interval.
978 * When a split child is split again, the new created interval is a direct child
979 * of the original parent. That is, there is no tree of split children stored, just a flat list.
980 * All split children are spilled to the same {@linkplain #spillSlot spill slot}.
981 *
982 * @param splitPos the position at which to split this interval
983 * @param allocator the register allocator context
984 * @return the child interval split off from this interval
985 */
986 Interval split(int splitPos, LinearScan allocator) {
987 assert operand.isVariable() : "cannot split fixed intervals";
988
989 // allocate new interval
990 Interval result = newSplitChild(allocator);
991
992 // split the ranges
993 Range prev = null;
994 Range cur = first;
995 while (cur != Range.EndMarker && cur.to <= splitPos) {
996 prev = cur;
997 cur = cur.next;
998 }
999 assert cur != Range.EndMarker : "split interval after end of last range";
1000
1001 if (cur.from < splitPos) {
1002 result.first = new Range(splitPos, cur.to, cur.next);
1003 cur.to = splitPos;
1004 cur.next = Range.EndMarker;
1005
1006 } else {
1007 assert prev != null : "split before start of first range";
1008 result.first = cur;
1009 prev.next = Range.EndMarker;
1010 }
1011 result.current = result.first;
1012 cachedTo = -1; // clear cached value
1013
1014 // split list of use positions
1015 result.usePosList = usePosList.splitAt(splitPos);
1016
1017 if (C1XOptions.DetailedAsserts) {
1018 for (int i = 0; i < usePosList.size(); i++) {
1019 assert usePosList.usePos(i) < splitPos;
1020 }
1021 for (int i = 0; i < result.usePosList.size(); i++) {
1022 assert result.usePosList.usePos(i) >= splitPos;
1023 }
1024 }
1025 return result;
1026 }
1027
1028 /**
1029 * Splits this interval at a specified position and returns
1030 * the head as a new interval (this interval is the tail).
1031 *
1032 * Currently, only the first range can be split, and the new interval must not have split positions
1033 */
1034 Interval splitFromStart(int splitPos, LinearScan allocator) {
1035 assert operand.isVariable() : "cannot split fixed intervals";
1036 assert splitPos > from() && splitPos < to() : "can only split inside interval";
1037 assert splitPos > first.from && splitPos <= first.to : "can only split inside first range";
1038 assert firstUsage(RegisterPriority.None) > splitPos : "can not split when use positions are present";
1039
1040 // allocate new interval
1041 Interval result = newSplitChild(allocator);
1042
1043 // the new interval has only one range (checked by assertion above,
1044 // so the splitting of the ranges is very simple
1045 result.addRange(first.from, splitPos);
1046
1047 if (splitPos == first.to) {
1048 assert first.next != Range.EndMarker : "must not be at end";
1049 first = first.next;
1050 } else {
1051 first.from = splitPos;
1052 }
1053
1054 return result;
1055 }
1056
1057 // returns true if the opId is inside the interval
1058 boolean covers(int opId, LIRInstruction.OperandMode mode) {
1059 Range cur = first;
1060
1061 while (cur != Range.EndMarker && cur.to < opId) {
1062 cur = cur.next;
1063 }
1064 if (cur != Range.EndMarker) {
1065 assert cur.to != cur.next.from : "ranges not separated";
1066
1067 if (mode == LIRInstruction.OperandMode.Output) {
1068 return cur.from <= opId && opId < cur.to;
1069 } else {
1070 return cur.from <= opId && opId <= cur.to;
1071 }
1072 }
1073 return false;
1074 }
1075
1076 // returns true if the interval has any hole between holeFrom and holeTo
1077 // (even if the hole has only the length 1)
1078 boolean hasHoleBetween(int holeFrom, int holeTo) {
1079 assert holeFrom < holeTo : "check";
1080 assert from() <= holeFrom && holeTo <= to() : "index out of interval";
1081
1082 Range cur = first;
1083 while (cur != Range.EndMarker) {
1084 assert cur.to < cur.next.from : "no space between ranges";
1085
1086 // hole-range starts before this range . hole
1087 if (holeFrom < cur.from) {
1088 return true;
1089
1090 // hole-range completely inside this range . no hole
1091 } else {
1092 if (holeTo <= cur.to) {
1093 return false;
1094
1095 // overlapping of hole-range with this range . hole
1096 } else {
1097 if (holeFrom <= cur.to) {
1098 return true;
1099 }
1100 }
1101 }
1102
1103 cur = cur.next;
1104 }
1105
1106 return false;
1107 }
1108
1109 @Override
1110 public String toString() {
1111 String from = "?";
1112 String to = "?";
1113 if (first != null && first != Range.EndMarker) {
1114 from = String.valueOf(from());
1115 to = String.valueOf(to());
1116 }
1117 String location = this.location == null ? "" : "@" + this.location.name();
1118 return operandNumber + ":" + operand + (operand.isRegister() ? "" : location) + "[" + from + "," + to + "]";
1119 }
1120
1121 /**
1122 * Gets the use position information for this interval.
1123 */
1124 public UsePosList usePosList() {
1125 return usePosList;
1126 }
1127
1128 /**
1129 * Gets a single line string for logging the details of this interval to a log stream.
1130 *
1131 * @param allocator the register allocator context
1132 */
1133 public String logString(LinearScan allocator) {
1134 StringBuilder buf = new StringBuilder(100);
1135 buf.append(operandNumber).append(':').append(operand).append(' ');
1136 if (!operand.isRegister()) {
1137 if (location != null) {
1138 buf.append("location{").append(location).append("} ");
1139 }
1140 }
1141
1142 buf.append("hints{").append(splitParent.operandNumber);
1143 Interval hint = locationHint(false, allocator);
1144 if (hint != null && hint.operandNumber != splitParent.operandNumber) {
1145 buf.append(", ").append(hint.operandNumber);
1146 }
1147 buf.append("} ranges{");
1148
1149 // print ranges
1150 Range cur = first;
1151 while (cur != Range.EndMarker) {
1152 if (cur != first) {
1153 buf.append(", ");
1154 }
1155 buf.append(cur);
1156 cur = cur.next;
1157 assert cur != null : "range list not closed with range sentinel";
1158 }
1159 buf.append("} uses{");
1160
1161 // print use positions
1162 int prev = 0;
1163 for (int i = usePosList.size() - 1; i >= 0; --i) {
1164 assert prev < usePosList.usePos(i) : "use positions not sorted";
1165 if (i != usePosList.size() - 1) {
1166 buf.append(", ");
1167 }
1168 buf.append(usePosList.usePos(i)).append(':').append(usePosList.registerPriority(i));
1169 prev = usePosList.usePos(i);
1170 }
1171 return buf.append("} spill-state{").append(spillState()).append("}").toString();
1172 }
1173 }