1 /* 2 * Copyright (c) 2015, 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 */ 23 package org.graalvm.compiler.lir.alloc.lsra.ssa; 24 25 import static org.graalvm.compiler.lir.LIRValueUtil.asVirtualStackSlot; 26 import static org.graalvm.compiler.lir.LIRValueUtil.isStackSlotValue; 27 import static org.graalvm.compiler.lir.LIRValueUtil.isVirtualStackSlot; 28 import static jdk.vm.ci.code.ValueUtil.asStackSlot; 29 import static jdk.vm.ci.code.ValueUtil.isStackSlot; 30 31 import java.util.Arrays; 32 33 import org.graalvm.compiler.debug.GraalError; 34 import org.graalvm.compiler.lir.LIRInstruction; 35 import org.graalvm.compiler.lir.VirtualStackSlot; 36 import org.graalvm.compiler.lir.alloc.lsra.Interval; 37 import org.graalvm.compiler.lir.alloc.lsra.LinearScan; 38 import org.graalvm.compiler.lir.alloc.lsra.MoveResolver; 39 import org.graalvm.compiler.lir.framemap.FrameMap; 40 import org.graalvm.compiler.lir.framemap.FrameMapBuilderTool; 41 42 import jdk.vm.ci.code.StackSlot; 43 import jdk.vm.ci.meta.AllocatableValue; 44 import jdk.vm.ci.meta.Value; 45 46 public final class SSAMoveResolver extends MoveResolver { 47 48 private static final int STACK_SLOT_IN_CALLER_FRAME_IDX = -1; 49 private int[] stackBlocked; 50 private final int firstVirtualStackIndex; 51 52 public SSAMoveResolver(LinearScan allocator) { 53 super(allocator); 54 FrameMapBuilderTool frameMapBuilderTool = (FrameMapBuilderTool) allocator.getFrameMapBuilder(); 55 FrameMap frameMap = frameMapBuilderTool.getFrameMap(); 56 this.stackBlocked = new int[frameMapBuilderTool.getNumberOfStackSlots()]; 57 this.firstVirtualStackIndex = !frameMap.frameNeedsAllocating() ? 0 : frameMap.currentFrameSize() + 1; 58 } 59 60 @Override 61 public boolean checkEmpty() { 62 for (int i = 0; i < stackBlocked.length; i++) { 63 assert stackBlocked[i] == 0 : "stack map must be empty before and after processing"; 64 } 65 return super.checkEmpty(); 66 } 67 68 @Override 69 protected void checkMultipleReads() { 70 // multiple reads are allowed in SSA LSRA 71 } 72 73 @Override 74 protected void verifyStackSlotMapping() { 75 // relax disjoint stack maps invariant 76 } 77 78 @Override 79 protected boolean areMultipleReadsAllowed() { 80 return true; 81 } 82 83 @Override 84 protected boolean mightBeBlocked(Value location) { 85 if (super.mightBeBlocked(location)) { 86 return true; 87 } 88 if (isStackSlotValue(location)) { 89 return true; 90 } 91 return false; 92 } 93 94 private int getStackArrayIndex(Value stackSlotValue) { 95 if (isStackSlot(stackSlotValue)) { 96 return getStackArrayIndex(asStackSlot(stackSlotValue)); 97 } 98 if (isVirtualStackSlot(stackSlotValue)) { 99 return getStackArrayIndex(asVirtualStackSlot(stackSlotValue)); 100 } 101 throw GraalError.shouldNotReachHere("value is not a stack slot: " + stackSlotValue); 102 } 103 104 private int getStackArrayIndex(StackSlot stackSlot) { 105 int stackIdx; 106 if (stackSlot.isInCallerFrame()) { 107 // incoming stack arguments can be ignored 108 stackIdx = STACK_SLOT_IN_CALLER_FRAME_IDX; 109 } else { 110 assert stackSlot.getRawAddFrameSize() : "Unexpected stack slot: " + stackSlot; 111 int offset = -stackSlot.getRawOffset(); 112 assert 0 <= offset && offset < firstVirtualStackIndex : String.format("Wrong stack slot offset: %d (first virtual stack slot index: %d", offset, firstVirtualStackIndex); 113 stackIdx = offset; 114 } 115 return stackIdx; 116 } 117 118 private int getStackArrayIndex(VirtualStackSlot virtualStackSlot) { 119 return firstVirtualStackIndex + virtualStackSlot.getId(); 120 } 121 122 @Override 123 protected void setValueBlocked(Value location, int direction) { 124 assert direction == 1 || direction == -1 : "out of bounds"; 125 if (isStackSlotValue(location)) { 126 int stackIdx = getStackArrayIndex(location); 127 if (stackIdx == STACK_SLOT_IN_CALLER_FRAME_IDX) { 128 // incoming stack arguments can be ignored 129 return; 130 } 131 if (stackIdx >= stackBlocked.length) { 132 stackBlocked = Arrays.copyOf(stackBlocked, stackIdx + 1); 133 } 134 stackBlocked[stackIdx] += direction; 135 } else { 136 super.setValueBlocked(location, direction); 137 } 138 } 139 140 @Override 141 protected int valueBlocked(Value location) { 142 if (isStackSlotValue(location)) { 143 int stackIdx = getStackArrayIndex(location); 144 if (stackIdx == STACK_SLOT_IN_CALLER_FRAME_IDX) { 145 // incoming stack arguments are always blocked (aka they can not be written) 146 return 1; 147 } 148 if (stackIdx >= stackBlocked.length) { 149 return 0; 150 } 151 return stackBlocked[stackIdx]; 152 } 153 return super.valueBlocked(location); 154 } 155 156 @Override 157 protected LIRInstruction createMove(AllocatableValue fromOpr, AllocatableValue toOpr, AllocatableValue fromLocation, AllocatableValue toLocation) { 158 if (isStackSlotValue(toLocation) && isStackSlotValue(fromLocation)) { 159 return getAllocator().getSpillMoveFactory().createStackMove(toOpr, fromOpr); 160 } 161 return super.createMove(fromOpr, toOpr, fromLocation, toLocation); 162 } 163 164 @Override 165 protected void breakCycle(int spillCandidate) { 166 if (spillCandidate != -1) { 167 super.breakCycle(spillCandidate); 168 return; 169 } 170 assert mappingFromSize() > 1; 171 // Arbitrarily select the first entry for spilling. 172 int stackSpillCandidate = 0; 173 Interval fromInterval = getMappingFrom(stackSpillCandidate); 174 // allocate new stack slot 175 VirtualStackSlot spillSlot = getAllocator().getFrameMapBuilder().allocateSpillSlot(fromInterval.kind()); 176 spillInterval(stackSpillCandidate, fromInterval, spillSlot); 177 } 178 }