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