src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/TraceGlobalMoveResolver.java
Index Unified diffs Context diffs Sdiffs Patch New Old Previous File Next File hotspot Sdiff src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace

src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/TraceGlobalMoveResolver.java

Print this page




  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 


src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/TraceGlobalMoveResolver.java
Index Unified diffs Context diffs Sdiffs Patch New Old Previous File Next File