23 package org.graalvm.compiler.lir.alloc.trace;
24
25 import static jdk.vm.ci.code.ValueUtil.asAllocatableValue;
26 import static jdk.vm.ci.code.ValueUtil.asRegister;
27 import static jdk.vm.ci.code.ValueUtil.asStackSlot;
28 import static jdk.vm.ci.code.ValueUtil.isIllegal;
29 import static jdk.vm.ci.code.ValueUtil.isRegister;
30 import static jdk.vm.ci.code.ValueUtil.isStackSlot;
31 import static org.graalvm.compiler.lir.LIRValueUtil.asVirtualStackSlot;
32 import static org.graalvm.compiler.lir.LIRValueUtil.isStackSlotValue;
33 import static org.graalvm.compiler.lir.LIRValueUtil.isVirtualStackSlot;
34 import static org.graalvm.compiler.lir.alloc.trace.TraceUtil.asShadowedRegisterValue;
35 import static org.graalvm.compiler.lir.alloc.trace.TraceUtil.isShadowedRegisterValue;
36
37 import java.util.ArrayList;
38 import java.util.Arrays;
39 import java.util.HashSet;
40
41 import org.graalvm.compiler.core.common.LIRKind;
42 import org.graalvm.compiler.core.common.alloc.RegisterAllocationConfig;
43 import org.graalvm.compiler.debug.Debug;
44 import org.graalvm.compiler.debug.DebugCounter;
45 import org.graalvm.compiler.debug.GraalError;
46 import org.graalvm.compiler.debug.Indent;
47 import org.graalvm.compiler.lir.LIRInsertionBuffer;
48 import org.graalvm.compiler.lir.LIRInstruction;
49 import org.graalvm.compiler.lir.VirtualStackSlot;
50 import org.graalvm.compiler.lir.framemap.FrameMap;
51 import org.graalvm.compiler.lir.framemap.FrameMapBuilder;
52 import org.graalvm.compiler.lir.framemap.FrameMapBuilderTool;
53 import org.graalvm.compiler.lir.gen.LIRGenerationResult;
54 import org.graalvm.compiler.lir.gen.LIRGeneratorTool.MoveFactory;
55 import org.graalvm.compiler.options.OptionValues;
56
57 import jdk.vm.ci.code.Architecture;
58 import jdk.vm.ci.code.RegisterArray;
59 import jdk.vm.ci.code.StackSlot;
60 import jdk.vm.ci.meta.AllocatableValue;
61 import jdk.vm.ci.meta.Value;
62
63 /**
64 */
65 public final class TraceGlobalMoveResolver extends TraceGlobalMoveResolutionPhase.MoveResolver {
66
67 private static final DebugCounter cycleBreakingSlotsAllocated = Debug.counter("TraceRA[cycleBreakingSlotsAllocated(global)]");
68 private static final DebugCounter cycleBreakingSlotsReused = Debug.counter("TraceRA[cycleBreakingSlotsReused(global)]");
69
70 private int insertIdx;
71 private LIRInsertionBuffer insertionBuffer; // buffer where moves are inserted
72
73 private final ArrayList<Value> mappingFrom;
74 private final ArrayList<Value> mappingFromStack;
75 private final ArrayList<AllocatableValue> mappingTo;
76 private final int[] registerBlocked;
77 private static final int STACK_SLOT_IN_CALLER_FRAME_IDX = -1;
78 private int[] stackBlocked;
79 private final int firstVirtualStackIndex;
80 private final MoveFactory spillMoveFactory;
81 private final FrameMapBuilder frameMapBuilder;
82 private final OptionValues options;
83 private final RegisterAllocationConfig registerAllocationConfig;
84 private final LIRGenerationResult res;
85
86 private void setValueBlocked(Value location, int direction) {
87 assert direction == 1 || direction == -1 : "out of bounds";
88 if (isStackSlotValue(location)) {
89 int stackIdx = getStackArrayIndex(location);
90 if (stackIdx == STACK_SLOT_IN_CALLER_FRAME_IDX) {
91 // incoming stack arguments can be ignored
92 return;
93 }
94 if (stackIdx >= stackBlocked.length) {
95 stackBlocked = Arrays.copyOf(stackBlocked, stackIdx + 1);
96 }
97 stackBlocked[stackIdx] += direction;
98 } else {
99 assert direction == 1 || direction == -1 : "out of bounds";
100 if (isRegister(location)) {
101 registerBlocked[asRegister(location).number] += direction;
102 } else {
103 throw GraalError.shouldNotReachHere("unhandled value " + location);
104 }
140 }
141
142 public TraceGlobalMoveResolver(LIRGenerationResult res, MoveFactory spillMoveFactory, RegisterAllocationConfig registerAllocationConfig, Architecture arch) {
143
144 this.mappingFrom = new ArrayList<>(8);
145 this.mappingFromStack = new ArrayList<>(8);
146 this.mappingTo = new ArrayList<>(8);
147 this.insertIdx = -1;
148 this.insertionBuffer = new LIRInsertionBuffer();
149
150 this.frameMapBuilder = res.getFrameMapBuilder();
151 this.spillMoveFactory = spillMoveFactory;
152 this.registerBlocked = new int[arch.getRegisters().size()];
153 this.registerAllocationConfig = registerAllocationConfig;
154
155 FrameMapBuilderTool frameMapBuilderTool = (FrameMapBuilderTool) frameMapBuilder;
156 this.stackBlocked = new int[frameMapBuilderTool.getNumberOfStackSlots()];
157
158 FrameMap frameMap = frameMapBuilderTool.getFrameMap();
159 this.firstVirtualStackIndex = !frameMap.frameNeedsAllocating() ? 0 : frameMap.currentFrameSize() + 1;
160 this.options = res.getLIR().getOptions();
161 this.res = res;
162 }
163
164 private boolean checkEmpty() {
165 for (int i = 0; i < stackBlocked.length; i++) {
166 assert stackBlocked[i] == 0 : "stack map must be empty before and after processing";
167 }
168 assert mappingFrom.size() == 0 && mappingTo.size() == 0 && mappingFromStack.size() == 0 : "list must be empty before and after processing";
169 for (int i = 0; i < getRegisters().size(); i++) {
170 assert registerBlocked[i] == 0 : "register map must be empty before and after processing";
171 }
172 return true;
173 }
174
175 private boolean verifyBeforeResolve() {
176 assert mappingFrom.size() == mappingTo.size() && mappingFrom.size() == mappingFromStack.size() : "length must be equal";
177 assert insertIdx != -1 : "insert position not set";
178
179 int i;
180 int j;
181 if (!areMultipleReadsAllowed()) {
211 usedRegs.clear();
212 for (i = 0; i < mappingTo.size(); i++) {
213 Value to = mappingTo.get(i);
214 if (isIllegal(to)) {
215 // After insertion the location may become illegal, so don't check it since multiple
216 // intervals might be illegal.
217 continue;
218 }
219 boolean unique = usedRegs.add(to);
220 assert unique : "cannot write to same register twice";
221 }
222
223 return true;
224 }
225
226 // mark assignedReg and assignedRegHi of the interval as blocked
227 private void block(Value location) {
228 if (mightBeBlocked(location)) {
229 assert areMultipleReadsAllowed() || valueBlocked(location) == 0 : "location already marked as used: " + location;
230 setValueBlocked(location, 1);
231 Debug.log("block %s", location);
232 }
233 }
234
235 // mark assignedReg and assignedRegHi of the interval as unblocked
236 private void unblock(Value location) {
237 if (mightBeBlocked(location)) {
238 assert valueBlocked(location) > 0 : "location already marked as unused: " + location;
239 setValueBlocked(location, -1);
240 Debug.log("unblock %s", location);
241 }
242 }
243
244 /**
245 * Checks if {@code to} is not blocked or is only blocked by {@code from}.
246 */
247 private boolean safeToProcessMove(Value fromLocation, Value toLocation) {
248 if (mightBeBlocked(toLocation)) {
249 if ((valueBlocked(toLocation) > 1 || (valueBlocked(toLocation) == 1 && !isMoveToSelf(fromLocation, toLocation)))) {
250 return false;
251 }
252 }
253
254 return true;
255 }
256
257 public static boolean isMoveToSelf(Value from, Value to) {
258 assert to != null;
259 if (to.equals(from)) {
260 return true;
307 insertionBuffer.init(list);
308 }
309
310 private void appendInsertionBuffer() {
311 if (insertionBuffer.initialized()) {
312 insertionBuffer.finish();
313 }
314 assert !insertionBuffer.initialized() : "must be uninitialized now";
315
316 insertIdx = -1;
317 }
318
319 private LIRInstruction insertMove(Value fromOperand, AllocatableValue toOperand) {
320 assert !fromOperand.equals(toOperand) : "from and to are equal: " + fromOperand + " vs. " + toOperand;
321 assert LIRKind.verifyMoveKinds(fromOperand.getValueKind(), fromOperand.getValueKind(), registerAllocationConfig) : "move between different types";
322 assert insertIdx != -1 : "must setup insert position first";
323
324 LIRInstruction move = createMove(fromOperand, toOperand);
325 insertionBuffer.append(insertIdx, move);
326
327 if (Debug.isLogEnabled()) {
328 Debug.log("insert move from %s to %s at %d", fromOperand, toOperand, insertIdx);
329 }
330 return move;
331 }
332
333 /**
334 * @param fromOpr Operand of the {@code from} interval
335 * @param toOpr Operand of the {@code to} interval
336 */
337 private LIRInstruction createMove(Value fromOpr, AllocatableValue toOpr) {
338 if (isStackSlotValue(toOpr) && isStackSlotValue(fromOpr)) {
339 return getSpillMoveFactory().createStackMove(toOpr, asAllocatableValue(fromOpr));
340 }
341 return getSpillMoveFactory().createMove(toOpr, fromOpr);
342 }
343
344 @SuppressWarnings("try")
345 private void resolveMappings() {
346 try (Indent indent = Debug.logAndIndent("resolveMapping")) {
347 assert verifyBeforeResolve();
348 if (Debug.isLogEnabled()) {
349 printMapping();
350 }
351
352 // Block all registers that are used as input operands of a move.
353 // When a register is blocked, no move to this register is emitted.
354 // This is necessary for detecting cycles in moves.
355 for (int i = mappingFrom.size() - 1; i >= 0; i--) {
356 Value from = mappingFrom.get(i);
357 block(from);
358 }
359
360 ArrayList<AllocatableValue> busySpillSlots = null;
361 while (mappingFrom.size() > 0) {
362 boolean processedInterval = false;
363
364 int spillCandidate = -1;
365 for (int i = mappingFrom.size() - 1; i >= 0; i--) {
366 Value fromLocation = mappingFrom.get(i);
367 AllocatableValue toLocation = mappingTo.get(i);
368 if (safeToProcessMove(fromLocation, toLocation)) {
394 }
395
396 if (!processedInterval) {
397 breakCycle(spillCandidate);
398 }
399 }
400 }
401
402 // check that all intervals have been processed
403 assert checkEmpty();
404 }
405
406 @SuppressWarnings("try")
407 private void breakCycle(int spillCandidate) {
408 // no move could be processed because there is a cycle in the move list
409 // (e.g. r1 . r2, r2 . r1), so one interval must be spilled to memory
410 assert spillCandidate != -1 : "no interval in register for spilling found";
411
412 // create a new spill interval and assign a stack slot to it
413 Value from = mappingFrom.get(spillCandidate);
414 try (Indent indent = Debug.logAndIndent("BreakCycle: %s", from)) {
415 AllocatableValue spillSlot = null;
416 if (TraceRegisterAllocationPhase.Options.TraceRAreuseStackSlotsForMoveResolutionCycleBreaking.getValue(options) && !isStackSlotValue(from)) {
417 // don't use the stack slot if from is already the stack slot
418 Value fromStack = mappingFromStack.get(spillCandidate);
419 if (fromStack != null) {
420 spillSlot = (AllocatableValue) fromStack;
421 cycleBreakingSlotsReused.increment();
422 Debug.log("reuse slot for spilling: %s", spillSlot);
423 }
424 }
425 if (spillSlot == null) {
426 spillSlot = frameMapBuilder.allocateSpillSlot(from.getValueKind());
427 cycleBreakingSlotsAllocated.increment();
428 Debug.log("created new slot for spilling: %s", spillSlot);
429 // insert a move from register to stack and update the mapping
430 LIRInstruction move = insertMove(from, spillSlot);
431 move.setComment(res, "TraceGlobalMoveResolver: breakCycle");
432 }
433 block(spillSlot);
434 mappingFrom.set(spillCandidate, spillSlot);
435 unblock(from);
436 }
437 }
438
439 @SuppressWarnings("try")
440 private void printMapping() {
441 try (Indent indent = Debug.logAndIndent("Mapping")) {
442 for (int i = mappingFrom.size() - 1; i >= 0; i--) {
443 Debug.log("move %s <- %s (%s)", mappingTo.get(i), mappingFrom.get(i), mappingFromStack.get(i));
444 }
445 }
446 }
447
448 public void setInsertPosition(ArrayList<LIRInstruction> insertList, int insertIdx) {
449 assert this.insertIdx == -1 : "use moveInsertPosition instead of setInsertPosition when data already set";
450
451 createInsertionBuffer(insertList);
452 this.insertIdx = insertIdx;
453 }
454
455 @Override
456 public void addMapping(Value from, AllocatableValue to, Value fromStack) {
457 if (Debug.isLogEnabled()) {
458 Debug.log("add move mapping from %s to %s", from, to);
459 }
460
461 assert !from.equals(to) : "from and to interval equal: " + from;
462 assert LIRKind.verifyMoveKinds(to.getValueKind(), from.getValueKind(), registerAllocationConfig) : String.format("Kind mismatch: %s vs. %s, from=%s, to=%s", from.getValueKind(),
463 to.getValueKind(), from, to);
464 assert fromStack == null || LIRKind.verifyMoveKinds(to.getValueKind(), fromStack.getValueKind(), registerAllocationConfig) : String.format("Kind mismatch: %s vs. %s, fromStack=%s, to=%s",
465 fromStack.getValueKind(),
466 to.getValueKind(), fromStack, to);
467 mappingFrom.add(from);
468 mappingFromStack.add(fromStack);
469 mappingTo.add(to);
470 }
471
472 public void resolveAndAppendMoves() {
473 if (hasMappings()) {
474 resolveMappings();
475 }
476 appendInsertionBuffer();
477 }
478
|
23 package org.graalvm.compiler.lir.alloc.trace;
24
25 import static jdk.vm.ci.code.ValueUtil.asAllocatableValue;
26 import static jdk.vm.ci.code.ValueUtil.asRegister;
27 import static jdk.vm.ci.code.ValueUtil.asStackSlot;
28 import static jdk.vm.ci.code.ValueUtil.isIllegal;
29 import static jdk.vm.ci.code.ValueUtil.isRegister;
30 import static jdk.vm.ci.code.ValueUtil.isStackSlot;
31 import static org.graalvm.compiler.lir.LIRValueUtil.asVirtualStackSlot;
32 import static org.graalvm.compiler.lir.LIRValueUtil.isStackSlotValue;
33 import static org.graalvm.compiler.lir.LIRValueUtil.isVirtualStackSlot;
34 import static org.graalvm.compiler.lir.alloc.trace.TraceUtil.asShadowedRegisterValue;
35 import static org.graalvm.compiler.lir.alloc.trace.TraceUtil.isShadowedRegisterValue;
36
37 import java.util.ArrayList;
38 import java.util.Arrays;
39 import java.util.HashSet;
40
41 import org.graalvm.compiler.core.common.LIRKind;
42 import org.graalvm.compiler.core.common.alloc.RegisterAllocationConfig;
43 import org.graalvm.compiler.debug.CounterKey;
44 import org.graalvm.compiler.debug.DebugContext;
45 import org.graalvm.compiler.debug.GraalError;
46 import org.graalvm.compiler.debug.Indent;
47 import org.graalvm.compiler.lir.LIR;
48 import org.graalvm.compiler.lir.LIRInsertionBuffer;
49 import org.graalvm.compiler.lir.LIRInstruction;
50 import org.graalvm.compiler.lir.VirtualStackSlot;
51 import org.graalvm.compiler.lir.framemap.FrameMap;
52 import org.graalvm.compiler.lir.framemap.FrameMapBuilder;
53 import org.graalvm.compiler.lir.framemap.FrameMapBuilderTool;
54 import org.graalvm.compiler.lir.gen.LIRGenerationResult;
55 import org.graalvm.compiler.lir.gen.LIRGeneratorTool.MoveFactory;
56 import org.graalvm.compiler.options.OptionValues;
57
58 import jdk.vm.ci.code.Architecture;
59 import jdk.vm.ci.code.RegisterArray;
60 import jdk.vm.ci.code.StackSlot;
61 import jdk.vm.ci.meta.AllocatableValue;
62 import jdk.vm.ci.meta.Value;
63
64 /**
65 */
66 public final class TraceGlobalMoveResolver extends TraceGlobalMoveResolutionPhase.MoveResolver {
67
68 private static final CounterKey cycleBreakingSlotsAllocated = DebugContext.counter("TraceRA[cycleBreakingSlotsAllocated(global)]");
69 private static final CounterKey cycleBreakingSlotsReused = DebugContext.counter("TraceRA[cycleBreakingSlotsReused(global)]");
70
71 private int insertIdx;
72 private LIRInsertionBuffer insertionBuffer; // buffer where moves are inserted
73
74 private final ArrayList<Value> mappingFrom;
75 private final ArrayList<Value> mappingFromStack;
76 private final ArrayList<AllocatableValue> mappingTo;
77 private final int[] registerBlocked;
78 private static final int STACK_SLOT_IN_CALLER_FRAME_IDX = -1;
79 private int[] stackBlocked;
80 private final int firstVirtualStackIndex;
81 private final MoveFactory spillMoveFactory;
82 private final FrameMapBuilder frameMapBuilder;
83 private final OptionValues options;
84 private final RegisterAllocationConfig registerAllocationConfig;
85 private final LIRGenerationResult res;
86 private final DebugContext debug;
87
88 private void setValueBlocked(Value location, int direction) {
89 assert direction == 1 || direction == -1 : "out of bounds";
90 if (isStackSlotValue(location)) {
91 int stackIdx = getStackArrayIndex(location);
92 if (stackIdx == STACK_SLOT_IN_CALLER_FRAME_IDX) {
93 // incoming stack arguments can be ignored
94 return;
95 }
96 if (stackIdx >= stackBlocked.length) {
97 stackBlocked = Arrays.copyOf(stackBlocked, stackIdx + 1);
98 }
99 stackBlocked[stackIdx] += direction;
100 } else {
101 assert direction == 1 || direction == -1 : "out of bounds";
102 if (isRegister(location)) {
103 registerBlocked[asRegister(location).number] += direction;
104 } else {
105 throw GraalError.shouldNotReachHere("unhandled value " + location);
106 }
142 }
143
144 public TraceGlobalMoveResolver(LIRGenerationResult res, MoveFactory spillMoveFactory, RegisterAllocationConfig registerAllocationConfig, Architecture arch) {
145
146 this.mappingFrom = new ArrayList<>(8);
147 this.mappingFromStack = new ArrayList<>(8);
148 this.mappingTo = new ArrayList<>(8);
149 this.insertIdx = -1;
150 this.insertionBuffer = new LIRInsertionBuffer();
151
152 this.frameMapBuilder = res.getFrameMapBuilder();
153 this.spillMoveFactory = spillMoveFactory;
154 this.registerBlocked = new int[arch.getRegisters().size()];
155 this.registerAllocationConfig = registerAllocationConfig;
156
157 FrameMapBuilderTool frameMapBuilderTool = (FrameMapBuilderTool) frameMapBuilder;
158 this.stackBlocked = new int[frameMapBuilderTool.getNumberOfStackSlots()];
159
160 FrameMap frameMap = frameMapBuilderTool.getFrameMap();
161 this.firstVirtualStackIndex = !frameMap.frameNeedsAllocating() ? 0 : frameMap.currentFrameSize() + 1;
162 this.res = res;
163 LIR lir = res.getLIR();
164 this.options = lir.getOptions();
165 this.debug = lir.getDebug();
166 }
167
168 private boolean checkEmpty() {
169 for (int i = 0; i < stackBlocked.length; i++) {
170 assert stackBlocked[i] == 0 : "stack map must be empty before and after processing";
171 }
172 assert mappingFrom.size() == 0 && mappingTo.size() == 0 && mappingFromStack.size() == 0 : "list must be empty before and after processing";
173 for (int i = 0; i < getRegisters().size(); i++) {
174 assert registerBlocked[i] == 0 : "register map must be empty before and after processing";
175 }
176 return true;
177 }
178
179 private boolean verifyBeforeResolve() {
180 assert mappingFrom.size() == mappingTo.size() && mappingFrom.size() == mappingFromStack.size() : "length must be equal";
181 assert insertIdx != -1 : "insert position not set";
182
183 int i;
184 int j;
185 if (!areMultipleReadsAllowed()) {
215 usedRegs.clear();
216 for (i = 0; i < mappingTo.size(); i++) {
217 Value to = mappingTo.get(i);
218 if (isIllegal(to)) {
219 // After insertion the location may become illegal, so don't check it since multiple
220 // intervals might be illegal.
221 continue;
222 }
223 boolean unique = usedRegs.add(to);
224 assert unique : "cannot write to same register twice";
225 }
226
227 return true;
228 }
229
230 // mark assignedReg and assignedRegHi of the interval as blocked
231 private void block(Value location) {
232 if (mightBeBlocked(location)) {
233 assert areMultipleReadsAllowed() || valueBlocked(location) == 0 : "location already marked as used: " + location;
234 setValueBlocked(location, 1);
235 debug.log("block %s", location);
236 }
237 }
238
239 // mark assignedReg and assignedRegHi of the interval as unblocked
240 private void unblock(Value location) {
241 if (mightBeBlocked(location)) {
242 assert valueBlocked(location) > 0 : "location already marked as unused: " + location;
243 setValueBlocked(location, -1);
244 debug.log("unblock %s", location);
245 }
246 }
247
248 /**
249 * Checks if {@code to} is not blocked or is only blocked by {@code from}.
250 */
251 private boolean safeToProcessMove(Value fromLocation, Value toLocation) {
252 if (mightBeBlocked(toLocation)) {
253 if ((valueBlocked(toLocation) > 1 || (valueBlocked(toLocation) == 1 && !isMoveToSelf(fromLocation, toLocation)))) {
254 return false;
255 }
256 }
257
258 return true;
259 }
260
261 public static boolean isMoveToSelf(Value from, Value to) {
262 assert to != null;
263 if (to.equals(from)) {
264 return true;
311 insertionBuffer.init(list);
312 }
313
314 private void appendInsertionBuffer() {
315 if (insertionBuffer.initialized()) {
316 insertionBuffer.finish();
317 }
318 assert !insertionBuffer.initialized() : "must be uninitialized now";
319
320 insertIdx = -1;
321 }
322
323 private LIRInstruction insertMove(Value fromOperand, AllocatableValue toOperand) {
324 assert !fromOperand.equals(toOperand) : "from and to are equal: " + fromOperand + " vs. " + toOperand;
325 assert LIRKind.verifyMoveKinds(fromOperand.getValueKind(), fromOperand.getValueKind(), registerAllocationConfig) : "move between different types";
326 assert insertIdx != -1 : "must setup insert position first";
327
328 LIRInstruction move = createMove(fromOperand, toOperand);
329 insertionBuffer.append(insertIdx, move);
330
331 if (debug.isLogEnabled()) {
332 debug.log("insert move from %s to %s at %d", fromOperand, toOperand, insertIdx);
333 }
334 return move;
335 }
336
337 /**
338 * @param fromOpr Operand of the {@code from} interval
339 * @param toOpr Operand of the {@code to} interval
340 */
341 private LIRInstruction createMove(Value fromOpr, AllocatableValue toOpr) {
342 if (isStackSlotValue(toOpr) && isStackSlotValue(fromOpr)) {
343 return getSpillMoveFactory().createStackMove(toOpr, asAllocatableValue(fromOpr));
344 }
345 return getSpillMoveFactory().createMove(toOpr, fromOpr);
346 }
347
348 @SuppressWarnings("try")
349 private void resolveMappings() {
350 try (Indent indent = debug.logAndIndent("resolveMapping")) {
351 assert verifyBeforeResolve();
352 if (debug.isLogEnabled()) {
353 printMapping();
354 }
355
356 // Block all registers that are used as input operands of a move.
357 // When a register is blocked, no move to this register is emitted.
358 // This is necessary for detecting cycles in moves.
359 for (int i = mappingFrom.size() - 1; i >= 0; i--) {
360 Value from = mappingFrom.get(i);
361 block(from);
362 }
363
364 ArrayList<AllocatableValue> busySpillSlots = null;
365 while (mappingFrom.size() > 0) {
366 boolean processedInterval = false;
367
368 int spillCandidate = -1;
369 for (int i = mappingFrom.size() - 1; i >= 0; i--) {
370 Value fromLocation = mappingFrom.get(i);
371 AllocatableValue toLocation = mappingTo.get(i);
372 if (safeToProcessMove(fromLocation, toLocation)) {
398 }
399
400 if (!processedInterval) {
401 breakCycle(spillCandidate);
402 }
403 }
404 }
405
406 // check that all intervals have been processed
407 assert checkEmpty();
408 }
409
410 @SuppressWarnings("try")
411 private void breakCycle(int spillCandidate) {
412 // no move could be processed because there is a cycle in the move list
413 // (e.g. r1 . r2, r2 . r1), so one interval must be spilled to memory
414 assert spillCandidate != -1 : "no interval in register for spilling found";
415
416 // create a new spill interval and assign a stack slot to it
417 Value from = mappingFrom.get(spillCandidate);
418 try (Indent indent = debug.logAndIndent("BreakCycle: %s", from)) {
419 AllocatableValue spillSlot = null;
420 if (TraceRegisterAllocationPhase.Options.TraceRAreuseStackSlotsForMoveResolutionCycleBreaking.getValue(options) && !isStackSlotValue(from)) {
421 // don't use the stack slot if from is already the stack slot
422 Value fromStack = mappingFromStack.get(spillCandidate);
423 if (fromStack != null) {
424 spillSlot = (AllocatableValue) fromStack;
425 cycleBreakingSlotsReused.increment(debug);
426 debug.log("reuse slot for spilling: %s", spillSlot);
427 }
428 }
429 if (spillSlot == null) {
430 spillSlot = frameMapBuilder.allocateSpillSlot(from.getValueKind());
431 cycleBreakingSlotsAllocated.increment(debug);
432 debug.log("created new slot for spilling: %s", spillSlot);
433 // insert a move from register to stack and update the mapping
434 LIRInstruction move = insertMove(from, spillSlot);
435 move.setComment(res, "TraceGlobalMoveResolver: breakCycle");
436 }
437 block(spillSlot);
438 mappingFrom.set(spillCandidate, spillSlot);
439 unblock(from);
440 }
441 }
442
443 @SuppressWarnings("try")
444 private void printMapping() {
445 try (Indent indent = debug.logAndIndent("Mapping")) {
446 for (int i = mappingFrom.size() - 1; i >= 0; i--) {
447 debug.log("move %s <- %s (%s)", mappingTo.get(i), mappingFrom.get(i), mappingFromStack.get(i));
448 }
449 }
450 }
451
452 public void setInsertPosition(ArrayList<LIRInstruction> insertList, int insertIdx) {
453 assert this.insertIdx == -1 : "use moveInsertPosition instead of setInsertPosition when data already set";
454
455 createInsertionBuffer(insertList);
456 this.insertIdx = insertIdx;
457 }
458
459 @Override
460 public void addMapping(Value from, AllocatableValue to, Value fromStack) {
461 if (debug.isLogEnabled()) {
462 debug.log("add move mapping from %s to %s", from, to);
463 }
464
465 assert !from.equals(to) : "from and to interval equal: " + from;
466 assert LIRKind.verifyMoveKinds(to.getValueKind(), from.getValueKind(), registerAllocationConfig) : String.format("Kind mismatch: %s vs. %s, from=%s, to=%s", from.getValueKind(),
467 to.getValueKind(), from, to);
468 assert fromStack == null || LIRKind.verifyMoveKinds(to.getValueKind(), fromStack.getValueKind(), registerAllocationConfig) : String.format("Kind mismatch: %s vs. %s, fromStack=%s, to=%s",
469 fromStack.getValueKind(),
470 to.getValueKind(), fromStack, to);
471 mappingFrom.add(from);
472 mappingFromStack.add(fromStack);
473 mappingTo.add(to);
474 }
475
476 public void resolveAndAppendMoves() {
477 if (hasMappings()) {
478 resolveMappings();
479 }
480 appendInsertionBuffer();
481 }
482
|