TraceLocalMoveResolver.java revision 12651:6ef01bd40ce2
178064Sume/*
278064Sume * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
378064Sume * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
478064Sume *
578064Sume * This code is free software; you can redistribute it and/or modify it
678064Sume * under the terms of the GNU General Public License version 2 only, as
778064Sume * published by the Free Software Foundation.
878064Sume *
978064Sume * This code is distributed in the hope that it will be useful, but WITHOUT
1078064Sume * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
1178064Sume * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
1278064Sume * version 2 for more details (a copy is included in the LICENSE file that
1378064Sume * accompanied this code).
1478064Sume *
1578064Sume * You should have received a copy of the GNU General Public License version
1678064Sume * 2 along with this work; if not, write to the Free Software Foundation,
1778064Sume * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
1878064Sume *
1978064Sume * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2078064Sume * or visit www.oracle.com if you need additional information or have any
2178064Sume * questions.
2278064Sume */
2378064Sumepackage org.graalvm.compiler.lir.alloc.trace.lsra;
2478064Sume
2578064Sumeimport static org.graalvm.compiler.lir.LIRValueUtil.asVirtualStackSlot;
2678064Sumeimport static org.graalvm.compiler.lir.LIRValueUtil.isStackSlotValue;
2778064Sumeimport static org.graalvm.compiler.lir.LIRValueUtil.isVirtualStackSlot;
2878064Sumeimport static jdk.vm.ci.code.ValueUtil.asRegister;
2978064Sumeimport static jdk.vm.ci.code.ValueUtil.asStackSlot;
3078064Sumeimport static jdk.vm.ci.code.ValueUtil.isIllegal;
3178064Sumeimport static jdk.vm.ci.code.ValueUtil.isRegister;
3278064Sumeimport static jdk.vm.ci.code.ValueUtil.isStackSlot;
3378064Sume
3478064Sumeimport java.util.ArrayList;
3578064Sumeimport java.util.Arrays;
3678064Sumeimport java.util.HashSet;
3778064Sumeimport java.util.List;
3878064Sume
3978064Sumeimport org.graalvm.compiler.core.common.LIRKind;
4078064Sumeimport org.graalvm.compiler.debug.Debug;
4178064Sumeimport org.graalvm.compiler.debug.DebugCounter;
4278064Sumeimport org.graalvm.compiler.debug.GraalError;
4378064Sumeimport org.graalvm.compiler.debug.Indent;
4478064Sumeimport org.graalvm.compiler.lir.LIRInsertionBuffer;
4578064Sumeimport org.graalvm.compiler.lir.LIRInstruction;
4678064Sumeimport org.graalvm.compiler.lir.VirtualStackSlot;
4778064Sumeimport org.graalvm.compiler.lir.alloc.trace.lsra.TraceLinearScanPhase.TraceLinearScan;
4878064Sumeimport org.graalvm.compiler.lir.framemap.FrameMap;
4978064Sumeimport org.graalvm.compiler.lir.framemap.FrameMapBuilderTool;
5078064Sume
5178064Sumeimport jdk.vm.ci.code.StackSlot;
5278064Sumeimport jdk.vm.ci.meta.AllocatableValue;
5378064Sumeimport jdk.vm.ci.meta.Constant;
5478064Sumeimport jdk.vm.ci.meta.JavaConstant;
5578064Sumeimport jdk.vm.ci.meta.Value;
5678064Sume
5778064Sume/**
5878064Sume */
5978064Sumefinal class TraceLocalMoveResolver {
6078064Sume
6178064Sume    private static final DebugCounter cycleBreakingSlotsAllocated = Debug.counter("TraceRA[cycleBreakingSlotsAllocated(local)]");
6278064Sume
6378064Sume    private static final int STACK_SLOT_IN_CALLER_FRAME_IDX = -1;
6478064Sume    private final TraceLinearScan allocator;
6578064Sume
6678064Sume    private int insertIdx;
6778064Sume    private LIRInsertionBuffer insertionBuffer; // buffer where moves are inserted
6878064Sume
6978064Sume    private final List<TraceInterval> mappingFrom;
7078064Sume    private final List<Constant> mappingFromOpr;
7178064Sume    private final List<TraceInterval> mappingTo;
7278064Sume    private final int[] registerBlocked;
7378064Sume
7478064Sume    private int[] stackBlocked;
7578064Sume    private final int firstVirtualStackIndex;
7678064Sume
7778064Sume    private int getStackArrayIndex(Value stackSlotValue) {
7878064Sume        if (isStackSlot(stackSlotValue)) {
7978064Sume            return getStackArrayIndex(asStackSlot(stackSlotValue));
8078064Sume        }
8178064Sume        if (isVirtualStackSlot(stackSlotValue)) {
8278064Sume            return getStackArrayIndex(asVirtualStackSlot(stackSlotValue));
8378064Sume        }
8478064Sume        throw GraalError.shouldNotReachHere("value is not a stack slot: " + stackSlotValue);
8578064Sume    }
8678064Sume
8778064Sume    private int getStackArrayIndex(StackSlot stackSlot) {
8878064Sume        int stackIdx;
8978064Sume        if (stackSlot.isInCallerFrame()) {
9078064Sume            // incoming stack arguments can be ignored
9178064Sume            stackIdx = STACK_SLOT_IN_CALLER_FRAME_IDX;
9278064Sume        } else {
9378064Sume            assert stackSlot.getRawAddFrameSize() : "Unexpected stack slot: " + stackSlot;
9478064Sume            int offset = -stackSlot.getRawOffset();
9578064Sume            assert 0 <= offset && offset < firstVirtualStackIndex : String.format("Wrong stack slot offset: %d (first virtual stack slot index: %d", offset, firstVirtualStackIndex);
9678064Sume            stackIdx = offset;
9778064Sume        }
9878064Sume        return stackIdx;
9978064Sume    }
10078064Sume
10178064Sume    private int getStackArrayIndex(VirtualStackSlot virtualStackSlot) {
10278064Sume        return firstVirtualStackIndex + virtualStackSlot.getId();
10378064Sume    }
10478064Sume
10578064Sume    protected void setValueBlocked(Value location, int direction) {
10678064Sume        assert direction == 1 || direction == -1 : "out of bounds";
10778064Sume        if (isStackSlotValue(location)) {
10878064Sume            int stackIdx = getStackArrayIndex(location);
10978064Sume            if (stackIdx == STACK_SLOT_IN_CALLER_FRAME_IDX) {
11078064Sume                // incoming stack arguments can be ignored
11178064Sume                return;
11278064Sume            }
11378064Sume            if (stackIdx >= stackBlocked.length) {
11478064Sume                stackBlocked = Arrays.copyOf(stackBlocked, stackIdx + 1);
11578064Sume            }
11678064Sume            stackBlocked[stackIdx] += direction;
11778064Sume        } else {
11878064Sume            assert direction == 1 || direction == -1 : "out of bounds";
11978064Sume            if (isRegister(location)) {
12078064Sume                registerBlocked[asRegister(location).number] += direction;
12178064Sume            } else {
12278064Sume                throw GraalError.shouldNotReachHere("unhandled value " + location);
12378064Sume            }
12478064Sume        }
12578064Sume    }
12678064Sume
12778064Sume    protected TraceInterval getMappingFrom(int i) {
12878064Sume        return mappingFrom.get(i);
12978064Sume    }
13078064Sume
13178064Sume    protected int mappingFromSize() {
13278064Sume        return mappingFrom.size();
13378064Sume    }
13478064Sume
13578064Sume    protected int valueBlocked(Value location) {
13678064Sume        if (isStackSlotValue(location)) {
13778064Sume            int stackIdx = getStackArrayIndex(location);
13878064Sume            if (stackIdx == STACK_SLOT_IN_CALLER_FRAME_IDX) {
13978064Sume                // incoming stack arguments are always blocked (aka they can not be written)
14078064Sume                return 1;
14178064Sume            }
14278064Sume            if (stackIdx >= stackBlocked.length) {
14378064Sume                return 0;
14478064Sume            }
14578064Sume            return stackBlocked[stackIdx];
14678064Sume        }
14778064Sume        if (isRegister(location)) {
14878064Sume            return registerBlocked[asRegister(location).number];
14978064Sume        }
15078064Sume        throw GraalError.shouldNotReachHere("unhandled value " + location);
15178064Sume    }
15278064Sume
15378064Sume    /*
15478064Sume     * TODO (je) remove?
15578064Sume     */
15678064Sume    protected static boolean areMultipleReadsAllowed() {
15778064Sume        return true;
15878064Sume    }
15978064Sume
16078064Sume    boolean hasMappings() {
16178064Sume        return mappingFrom.size() > 0;
16278064Sume    }
16378064Sume
16478064Sume    protected TraceLinearScan getAllocator() {
16578064Sume        return allocator;
16678064Sume    }
16778064Sume
16878064Sume    protected TraceLocalMoveResolver(TraceLinearScan allocator) {
16978064Sume
17078064Sume        this.allocator = allocator;
17178064Sume        this.mappingFrom = new ArrayList<>(8);
17278064Sume        this.mappingFromOpr = new ArrayList<>(8);
17378064Sume        this.mappingTo = new ArrayList<>(8);
17478064Sume        this.insertIdx = -1;
17578064Sume        this.insertionBuffer = new LIRInsertionBuffer();
17678064Sume        this.registerBlocked = new int[allocator.getRegisters().size()];
17778064Sume        FrameMapBuilderTool frameMapBuilderTool = (FrameMapBuilderTool) allocator.getFrameMapBuilder();
17878064Sume        FrameMap frameMap = frameMapBuilderTool.getFrameMap();
17978064Sume        this.stackBlocked = new int[frameMapBuilderTool.getNumberOfStackSlots()];
18078064Sume        this.firstVirtualStackIndex = !frameMap.frameNeedsAllocating() ? 0 : frameMap.currentFrameSize() + 1;
18178064Sume    }
18278064Sume
18378064Sume    protected boolean checkEmpty() {
18478064Sume        assert mappingFrom.size() == 0 && mappingFromOpr.size() == 0 && mappingTo.size() == 0 : "list must be empty before and after processing";
18578064Sume        for (int i = 0; i < stackBlocked.length; i++) {
18678064Sume            assert stackBlocked[i] == 0 : "stack map must be empty before and after processing";
18778064Sume        }
18878064Sume        for (int i = 0; i < getAllocator().getRegisters().size(); i++) {
18978064Sume            assert registerBlocked[i] == 0 : "register map must be empty before and after processing";
19078064Sume        }
19178064Sume        checkMultipleReads();
19278064Sume        return true;
19378064Sume    }
19478064Sume
19578064Sume    protected void checkMultipleReads() {
19678064Sume        // multiple reads are allowed in SSA LSRA
19778064Sume    }
19878064Sume
19978064Sume    private boolean verifyBeforeResolve() {
20078064Sume        assert mappingFrom.size() == mappingFromOpr.size() : "length must be equal";
20178064Sume        assert mappingFrom.size() == mappingTo.size() : "length must be equal";
20278064Sume        assert insertIdx != -1 : "insert position not set";
20378064Sume
20478064Sume        int i;
20578064Sume        int j;
20678064Sume        if (!areMultipleReadsAllowed()) {
20778064Sume            for (i = 0; i < mappingFrom.size(); i++) {
20878064Sume                for (j = i + 1; j < mappingFrom.size(); j++) {
20978064Sume                    assert mappingFrom.get(i) == null || mappingFrom.get(i) != mappingFrom.get(j) : "cannot read from same interval twice";
21078064Sume                }
21178064Sume            }
21278064Sume        }
21378064Sume
21478064Sume        for (i = 0; i < mappingTo.size(); i++) {
21578064Sume            for (j = i + 1; j < mappingTo.size(); j++) {
21678064Sume                assert mappingTo.get(i) != mappingTo.get(j) : "cannot write to same interval twice";
21778064Sume            }
21878064Sume        }
21978064Sume
22078064Sume        HashSet<Value> usedRegs = new HashSet<>();
22178064Sume        if (!areMultipleReadsAllowed()) {
22278064Sume            for (i = 0; i < mappingFrom.size(); i++) {
22378064Sume                TraceInterval interval = mappingFrom.get(i);
22478064Sume                if (interval != null && !isIllegal(interval.location())) {
22578064Sume                    boolean unique = usedRegs.add(interval.location());
22678064Sume                    assert unique : "cannot read from same register twice";
22778064Sume                }
22878064Sume            }
22978064Sume        }
23078064Sume
23178064Sume        usedRegs.clear();
23278064Sume        for (i = 0; i < mappingTo.size(); i++) {
23378064Sume            TraceInterval interval = mappingTo.get(i);
23478064Sume            if (isIllegal(interval.location())) {
23578064Sume                // After insertion the location may become illegal, so don't check it since multiple
23678064Sume                // intervals might be illegal.
23778064Sume                continue;
23878064Sume            }
23978064Sume            boolean unique = usedRegs.add(interval.location());
24078064Sume            assert unique : "cannot write to same register twice";
24178064Sume        }
24278064Sume
24378064Sume        verifyStackSlotMapping();
24478064Sume
24578064Sume        return true;
24678064Sume    }
24778064Sume
24878064Sume    protected void verifyStackSlotMapping() {
24978064Sume        // relax disjoint stack maps invariant
25078064Sume    }
25178064Sume
25278064Sume    // mark assignedReg and assignedRegHi of the interval as blocked
25378064Sume    private void blockRegisters(TraceInterval interval) {
25478064Sume        Value location = interval.location();
25578064Sume        if (mightBeBlocked(location)) {
25678064Sume            assert areMultipleReadsAllowed() || valueBlocked(location) == 0 : "location already marked as used: " + location;
25778064Sume            int direction = 1;
25878064Sume            setValueBlocked(location, direction);
25978064Sume            Debug.log("block %s", location);
26078064Sume        }
26178064Sume    }
26278064Sume
26378064Sume    // mark assignedReg and assignedRegHi of the interval as unblocked
26478064Sume    private void unblockRegisters(TraceInterval interval) {
26578064Sume        Value location = interval.location();
26678064Sume        if (mightBeBlocked(location)) {
26778064Sume            assert valueBlocked(location) > 0 : "location already marked as unused: " + location;
26878064Sume            setValueBlocked(location, -1);
26978064Sume            Debug.log("unblock %s", location);
27078064Sume        }
27178064Sume    }
27278064Sume
27378064Sume    /**
27478064Sume     * Checks if the {@linkplain TraceInterval#location() location} of {@code to} is not blocked or
27578064Sume     * is only blocked by {@code from}.
27678064Sume     */
27778064Sume    private boolean safeToProcessMove(TraceInterval from, TraceInterval to) {
27878064Sume        Value fromReg = from != null ? from.location() : null;
27978064Sume
28078064Sume        Value location = to.location();
28178064Sume        if (mightBeBlocked(location)) {
28278064Sume            if ((valueBlocked(location) > 1 || (valueBlocked(location) == 1 && !isMoveToSelf(fromReg, location)))) {
28378064Sume                return false;
28478064Sume            }
28578064Sume        }
28678064Sume
28778064Sume        return true;
28878064Sume    }
28978064Sume
29078064Sume    protected static boolean isMoveToSelf(Value from, Value to) {
29178064Sume        assert to != null;
29278064Sume        if (to.equals(from)) {
29378064Sume            return true;
29478064Sume        }
29578064Sume        if (from != null && isRegister(from) && isRegister(to) && asRegister(from).equals(asRegister(to))) {
29678064Sume            assert LIRKind.verifyMoveKinds(to.getValueKind(), from.getValueKind()) : String.format("Same register but Kind mismatch %s <- %s", to, from);
29778064Sume            return true;
29878064Sume        }
29978064Sume        return false;
30078064Sume    }
30178064Sume
30278064Sume    protected static boolean mightBeBlocked(Value location) {
30378064Sume        if (isRegister(location)) {
30478064Sume            return true;
30578064Sume        }
30678064Sume        if (isStackSlotValue(location)) {
30778064Sume            return true;
30878064Sume        }
30978064Sume        return false;
31078064Sume    }
31178064Sume
31278064Sume    private void createInsertionBuffer(List<LIRInstruction> list) {
31378064Sume        assert !insertionBuffer.initialized() : "overwriting existing buffer";
31478064Sume        insertionBuffer.init(list);
31578064Sume    }
31678064Sume
31778064Sume    private void appendInsertionBuffer() {
31878064Sume        if (insertionBuffer.initialized()) {
31978064Sume            insertionBuffer.finish();
32078064Sume        }
32178064Sume        assert !insertionBuffer.initialized() : "must be uninitialized now";
32278064Sume
32378064Sume        insertIdx = -1;
32478064Sume    }
32578064Sume
32678064Sume    private void insertMove(TraceInterval fromInterval, TraceInterval toInterval) {
32778064Sume        assert !fromInterval.operand.equals(toInterval.operand) : "from and to interval equal: " + fromInterval;
32878064Sume        assert LIRKind.verifyMoveKinds(toInterval.kind(), fromInterval.kind()) : "move between different types";
32978064Sume        assert insertIdx != -1 : "must setup insert position first";
33078064Sume
33178064Sume        insertionBuffer.append(insertIdx, createMove(fromInterval.operand, toInterval.operand, fromInterval.location(), toInterval.location()));
33278064Sume
33378064Sume        if (Debug.isLogEnabled()) {
33478064Sume            Debug.log("insert move from %s to %s at %d", fromInterval, toInterval, insertIdx);
33578064Sume        }
33678064Sume    }
33778064Sume
33878064Sume    /**
33978064Sume     * @param fromOpr {@link TraceInterval#operand operand} of the {@code from} interval
34078064Sume     * @param toOpr {@link TraceInterval#operand operand} of the {@code to} interval
34178064Sume     * @param fromLocation {@link TraceInterval#location() location} of the {@code to} interval
34278064Sume     * @param toLocation {@link TraceInterval#location() location} of the {@code to} interval
34378064Sume     */
34478064Sume    protected LIRInstruction createMove(AllocatableValue fromOpr, AllocatableValue toOpr, AllocatableValue fromLocation, AllocatableValue toLocation) {
34578064Sume        if (isStackSlotValue(toLocation) && isStackSlotValue(fromLocation)) {
34678064Sume            return getAllocator().getSpillMoveFactory().createStackMove(toOpr, fromOpr);
34778064Sume        }
34878064Sume        return getAllocator().getSpillMoveFactory().createMove(toOpr, fromOpr);
34978064Sume    }
35078064Sume
35178064Sume    private void insertMove(Constant fromOpr, TraceInterval toInterval) {
35278064Sume        assert insertIdx != -1 : "must setup insert position first";
35378064Sume
35478064Sume        AllocatableValue toOpr = toInterval.operand;
35578064Sume        LIRInstruction move = getAllocator().getSpillMoveFactory().createLoad(toOpr, fromOpr);
35678064Sume        insertionBuffer.append(insertIdx, move);
35778064Sume
35878064Sume        if (Debug.isLogEnabled()) {
35978064Sume            Debug.log("insert move from value %s to %s at %d", fromOpr, toInterval, insertIdx);
36078064Sume        }
36178064Sume    }
36278064Sume
36378064Sume    @SuppressWarnings("try")
36478064Sume    private void resolveMappings() {
36578064Sume        try (Indent indent = Debug.logAndIndent("resolveMapping")) {
36678064Sume            assert verifyBeforeResolve();
36778064Sume            if (Debug.isLogEnabled()) {
36878064Sume                printMapping();
36978064Sume            }
37078064Sume
37178064Sume            // Block all registers that are used as input operands of a move.
37278064Sume            // When a register is blocked, no move to this register is emitted.
37378064Sume            // This is necessary for detecting cycles in moves.
37478064Sume            int i;
37578064Sume            for (i = mappingFrom.size() - 1; i >= 0; i--) {
37678064Sume                TraceInterval fromInterval = mappingFrom.get(i);
37778064Sume                if (fromInterval != null) {
37878064Sume                    blockRegisters(fromInterval);
37978064Sume                }
38078064Sume            }
38178064Sume
38278064Sume            ArrayList<AllocatableValue> busySpillSlots = null;
38378064Sume            while (mappingFrom.size() > 0) {
38478064Sume                boolean processedInterval = false;
38578064Sume
38678064Sume                int spillCandidate = -1;
38778064Sume                for (i = mappingFrom.size() - 1; i >= 0; i--) {
38878064Sume                    TraceInterval fromInterval = mappingFrom.get(i);
38978064Sume                    TraceInterval toInterval = mappingTo.get(i);
39078064Sume
39178064Sume                    if (safeToProcessMove(fromInterval, toInterval)) {
39278064Sume                        // this interval can be processed because target is free
39378064Sume                        if (fromInterval != null) {
39478064Sume                            insertMove(fromInterval, toInterval);
39578064Sume                            unblockRegisters(fromInterval);
39678064Sume                        } else {
39778064Sume                            insertMove(mappingFromOpr.get(i), toInterval);
39878064Sume                        }
39978064Sume                        if (isStackSlotValue(toInterval.location())) {
40078064Sume                            if (busySpillSlots == null) {
40178064Sume                                busySpillSlots = new ArrayList<>(2);
40278064Sume                            }
40378064Sume                            busySpillSlots.add(toInterval.location());
40478064Sume                        }
40578064Sume                        mappingFrom.remove(i);
40678064Sume                        mappingFromOpr.remove(i);
40778064Sume                        mappingTo.remove(i);
40878064Sume
40978064Sume                        processedInterval = true;
41078064Sume                    } else if (fromInterval != null && isRegister(fromInterval.location()) && (busySpillSlots == null || !busySpillSlots.contains(fromInterval.spillSlot()))) {
41178064Sume                        // this interval cannot be processed now because target is not free
41278064Sume                        // it starts in a register, so it is a possible candidate for spilling
41378064Sume                        spillCandidate = i;
41478064Sume                    }
41578064Sume                }
41678064Sume
41778064Sume                if (!processedInterval) {
41878064Sume                    breakCycle(spillCandidate);
41978064Sume                }
42078064Sume            }
42178064Sume        }
42278064Sume
42378064Sume        // check that all intervals have been processed
42478064Sume        assert checkEmpty();
42578064Sume    }
42678064Sume
42778064Sume    protected void breakCycle(int spillCandidate) {
42878064Sume        if (spillCandidate != -1) {
42978064Sume            // no move could be processed because there is a cycle in the move list
43078064Sume            // (e.g. r1 . r2, r2 . r1), so one interval must be spilled to memory
43178064Sume            assert spillCandidate != -1 : "no interval in register for spilling found";
43278064Sume
43378064Sume            // create a new spill interval and assign a stack slot to it
43478064Sume            TraceInterval fromInterval1 = mappingFrom.get(spillCandidate);
43578064Sume            // do not allocate a new spill slot for temporary interval, but
43678064Sume            // use spill slot assigned to fromInterval. Otherwise moves from
43778064Sume            // one stack slot to another can happen (not allowed by LIRAssembler
43878064Sume            AllocatableValue spillSlot1 = fromInterval1.spillSlot();
43978064Sume            if (spillSlot1 == null) {
44078064Sume                spillSlot1 = getAllocator().getFrameMapBuilder().allocateSpillSlot(fromInterval1.kind());
44178064Sume                fromInterval1.setSpillSlot(spillSlot1);
44278064Sume                cycleBreakingSlotsAllocated.increment();
44378064Sume            }
44478064Sume            spillInterval(spillCandidate, fromInterval1, spillSlot1);
44578064Sume            return;
44678064Sume        }
44778064Sume        assert mappingFromSize() > 1;
44878064Sume        // Arbitrarily select the first entry for spilling.
44978064Sume        int stackSpillCandidate = 0;
45078064Sume        TraceInterval fromInterval = getMappingFrom(stackSpillCandidate);
45178064Sume        // allocate new stack slot
45278064Sume        VirtualStackSlot spillSlot = getAllocator().getFrameMapBuilder().allocateSpillSlot(fromInterval.kind());
45378064Sume        spillInterval(stackSpillCandidate, fromInterval, spillSlot);
45478064Sume    }
45578064Sume
45678064Sume    protected void spillInterval(int spillCandidate, TraceInterval fromInterval, AllocatableValue spillSlot) {
45778064Sume        assert mappingFrom.get(spillCandidate).equals(fromInterval);
45878064Sume        TraceInterval spillInterval = getAllocator().createDerivedInterval(fromInterval);
45978064Sume
46078064Sume        // add a dummy range because real position is difficult to calculate
46178064Sume        // Note: this range is a special case when the integrity of the allocation is
46278064Sume        // checked
46378064Sume        spillInterval.addRange(1, 2);
46478064Sume
46578064Sume        spillInterval.assignLocation(spillSlot);
46678064Sume
46778064Sume        if (Debug.isLogEnabled()) {
46878064Sume            Debug.log("created new Interval for spilling: %s", spillInterval);
46978064Sume        }
47078064Sume        blockRegisters(spillInterval);
47178064Sume
47278064Sume        // insert a move from register to stack and update the mapping
47378064Sume        insertMove(fromInterval, spillInterval);
47478064Sume        mappingFrom.set(spillCandidate, spillInterval);
47578064Sume        unblockRegisters(fromInterval);
47678064Sume    }
47778064Sume
47878064Sume    @SuppressWarnings("try")
47978064Sume    private void printMapping() {
48078064Sume        try (Indent indent = Debug.logAndIndent("Mapping")) {
48178064Sume            for (int i = mappingFrom.size() - 1; i >= 0; i--) {
48278064Sume                TraceInterval fromInterval = mappingFrom.get(i);
48378064Sume                TraceInterval toInterval = mappingTo.get(i);
48478064Sume                String from;
48578064Sume                Value to = toInterval.location();
48678064Sume                if (fromInterval == null) {
48778064Sume                    from = mappingFromOpr.get(i).toString();
48878064Sume                } else {
48978064Sume                    from = fromInterval.location().toString();
49078064Sume                }
49178064Sume                Debug.log("move %s <- %s", from, to);
49278064Sume            }
49378064Sume        }
49478064Sume    }
49578064Sume
49678064Sume    void setInsertPosition(List<LIRInstruction> insertList, int insertIdx) {
49778064Sume        assert this.insertIdx == -1 : "use moveInsertPosition instead of setInsertPosition when data already set";
49878064Sume
49978064Sume        createInsertionBuffer(insertList);
50078064Sume        this.insertIdx = insertIdx;
50178064Sume    }
50278064Sume
50378064Sume    void moveInsertPosition(List<LIRInstruction> newInsertList, int newInsertIdx) {
50478064Sume        if (insertionBuffer.lirList() != null && (insertionBuffer.lirList() != newInsertList || this.insertIdx != newInsertIdx)) {
50578064Sume            // insert position changed . resolve current mappings
50678064Sume            resolveMappings();
50778064Sume        }
50878064Sume
50978064Sume        assert insertionBuffer.lirList() != newInsertList || newInsertIdx >= insertIdx : String.format("Decreasing insert index: old=%d new=%d", insertIdx, newInsertIdx);
51078064Sume
51178064Sume        if (insertionBuffer.lirList() != newInsertList) {
51278064Sume            // block changed . append insertionBuffer because it is
51378064Sume            // bound to a specific block and create a new insertionBuffer
51478064Sume            appendInsertionBuffer();
51578064Sume            createInsertionBuffer(newInsertList);
51678064Sume        }
51778064Sume
51878064Sume        this.insertIdx = newInsertIdx;
51978064Sume    }
52078064Sume
52178064Sume    public void addMapping(TraceInterval fromInterval, TraceInterval toInterval) {
52278064Sume
52378064Sume        if (isIllegal(toInterval.location()) && toInterval.canMaterialize()) {
52478064Sume            if (Debug.isLogEnabled()) {
52578064Sume                Debug.log("no store to rematerializable interval %s needed", toInterval);
52678064Sume            }
52778064Sume            return;
52878064Sume        }
52978064Sume        if (isIllegal(fromInterval.location()) && fromInterval.canMaterialize()) {
53078064Sume            // Instead of a reload, re-materialize the value
53178064Sume            JavaConstant rematValue = fromInterval.getMaterializedValue();
53278064Sume            addMapping(rematValue, toInterval);
53378064Sume            return;
53478064Sume        }
53578064Sume        if (Debug.isLogEnabled()) {
53678064Sume            Debug.log("add move mapping from %s to %s", fromInterval, toInterval);
53778064Sume        }
53878064Sume
53978064Sume        assert !fromInterval.operand.equals(toInterval.operand) : "from and to interval equal: " + fromInterval;
54078064Sume        assert LIRKind.verifyMoveKinds(toInterval.kind(), fromInterval.kind()) : String.format("Kind mismatch: %s vs. %s, from=%s, to=%s", fromInterval.kind(), toInterval.kind(), fromInterval,
54178064Sume                        toInterval);
54278064Sume        mappingFrom.add(fromInterval);
54378064Sume        mappingFromOpr.add(null);
54478064Sume        mappingTo.add(toInterval);
54578064Sume    }
54678064Sume
54778064Sume    public void addMapping(Constant fromOpr, TraceInterval toInterval) {
54878064Sume        if (Debug.isLogEnabled()) {
54978064Sume            Debug.log("add move mapping from %s to %s", fromOpr, toInterval);
55078064Sume        }
55178064Sume
55278064Sume        mappingFrom.add(null);
55378064Sume        mappingFromOpr.add(fromOpr);
55478064Sume        mappingTo.add(toInterval);
55578064Sume    }
55678064Sume
55778064Sume    void resolveAndAppendMoves() {
55878064Sume        if (hasMappings()) {
55978064Sume            resolveMappings();
56078064Sume        }
56178064Sume        appendInsertionBuffer();
56278064Sume    }
56378064Sume}
56478064Sume