1 /*
   2  * Copyright (c) 2016, 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.trace.bu;
  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.isIllegal;
  28 import static jdk.vm.ci.code.ValueUtil.isRegister;
  29 import static org.graalvm.compiler.core.common.GraalOptions.DetailedAsserts;
  30 import static org.graalvm.compiler.lir.LIRValueUtil.asVariable;
  31 import static org.graalvm.compiler.lir.LIRValueUtil.isConstantValue;
  32 import static org.graalvm.compiler.lir.LIRValueUtil.isStackSlotValue;
  33 import static org.graalvm.compiler.lir.LIRValueUtil.isVariable;
  34 
  35 import java.util.ArrayList;
  36 import java.util.BitSet;
  37 import java.util.Collections;
  38 import java.util.EnumSet;
  39 
  40 import org.graalvm.compiler.core.common.alloc.RegisterAllocationConfig;
  41 import org.graalvm.compiler.core.common.alloc.RegisterAllocationConfig.AllocatableRegisters;
  42 import org.graalvm.compiler.core.common.alloc.Trace;
  43 import org.graalvm.compiler.core.common.alloc.TraceBuilderResult;
  44 import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
  45 import org.graalvm.compiler.debug.DebugContext;
  46 import org.graalvm.compiler.debug.Indent;
  47 import org.graalvm.compiler.lir.InstructionValueProcedure;
  48 import org.graalvm.compiler.lir.LIR;
  49 import org.graalvm.compiler.lir.LIRInstruction;
  50 import org.graalvm.compiler.lir.LIRInstruction.OperandFlag;
  51 import org.graalvm.compiler.lir.LIRInstruction.OperandMode;
  52 import org.graalvm.compiler.lir.LIRValueUtil;
  53 import org.graalvm.compiler.lir.RedundantMoveElimination;
  54 import org.graalvm.compiler.lir.StandardOp;
  55 import org.graalvm.compiler.lir.StandardOp.BlockEndOp;
  56 import org.graalvm.compiler.lir.StandardOp.JumpOp;
  57 import org.graalvm.compiler.lir.StandardOp.LabelOp;
  58 import org.graalvm.compiler.lir.Variable;
  59 import org.graalvm.compiler.lir.VirtualStackSlot;
  60 import org.graalvm.compiler.lir.alloc.OutOfRegistersException;
  61 import org.graalvm.compiler.lir.alloc.trace.GlobalLivenessInfo;
  62 import org.graalvm.compiler.lir.alloc.trace.TraceAllocationPhase;
  63 import org.graalvm.compiler.lir.alloc.trace.TraceAllocationPhase.TraceAllocationContext;
  64 import org.graalvm.compiler.lir.alloc.trace.TraceGlobalMoveResolutionPhase;
  65 import org.graalvm.compiler.lir.alloc.trace.TraceGlobalMoveResolver;
  66 import org.graalvm.compiler.lir.alloc.trace.TraceRegisterAllocationPhase;
  67 import org.graalvm.compiler.lir.gen.LIRGenerationResult;
  68 import org.graalvm.compiler.lir.gen.LIRGeneratorTool.MoveFactory;
  69 import org.graalvm.compiler.lir.ssa.SSAUtil;
  70 
  71 import jdk.vm.ci.code.Register;
  72 import jdk.vm.ci.code.RegisterArray;
  73 import jdk.vm.ci.code.RegisterAttributes;
  74 import jdk.vm.ci.code.RegisterValue;
  75 import jdk.vm.ci.code.TargetDescription;
  76 import jdk.vm.ci.common.JVMCIError;
  77 import jdk.vm.ci.meta.AllocatableValue;
  78 import jdk.vm.ci.meta.PlatformKind;
  79 import jdk.vm.ci.meta.Value;
  80 
  81 /**
  82  * Allocates registers within a trace in a greedy, bottom-up fashion. The liveness information is
  83  * computed on the fly as the instructions are traversed instead of computing it in a separate pass.
  84  * The goal of this allocator is to provide a simple and fast algorithm for situations where code
  85  * quality is not the primary target.
  86  *
  87  * This implementation does not (yet) exploit hinting information and might introduce multiple spill
  88  * moves to the same stack slot (which are likely to be remove by {@link RedundantMoveElimination}.
  89  *
  90  * The current implementation cannot deal with {@link AbstractBlockBase blocks} with edges to
  91  * compiled exception handlers since it might introduce spill code after the {@link LIRInstruction
  92  * instruction} that triggers the exception.
  93  */
  94 public final class BottomUpAllocator extends TraceAllocationPhase<TraceAllocationContext> {
  95     private final TargetDescription target;
  96     private final LIRGenerationResult lirGenRes;
  97     private final MoveFactory spillMoveFactory;
  98     private final RegisterAllocationConfig registerAllocationConfig;
  99     private final RegisterArray callerSaveRegs;
 100     private final RegisterAttributes[] registerAttributes;
 101     private final BitSet allocatedBlocks;
 102     private final TraceBuilderResult resultTraces;
 103     private final TraceGlobalMoveResolver moveResolver;
 104     private final DebugContext debug;
 105 
 106     /**
 107      * Maps from {@link Variable#index} to a spill stack slot. If
 108      * {@linkplain org.graalvm.compiler.lir.alloc.trace.TraceRegisterAllocationPhase.Options#TraceRACacheStackSlots
 109      * enabled} a {@link Variable} is always assigned to the same stack slot.
 110      */
 111     private final AllocatableValue[] stackSlots;
 112 
 113     private final ArrayList<LIRInstruction> insertInstructionsBefore;
 114     private final ArrayList<LIRInstruction> insertInstructionsAfter;
 115     private final boolean neverSpillConstants;
 116 
 117     private final GlobalLivenessInfo livenessInfo;
 118 
 119     public BottomUpAllocator(TargetDescription target, LIRGenerationResult lirGenRes, MoveFactory spillMoveFactory, RegisterAllocationConfig registerAllocationConfig,
 120                     AllocatableValue[] cachedStackSlots, TraceBuilderResult resultTraces, boolean neverSpillConstant, GlobalLivenessInfo livenessInfo) {
 121         this.target = target;
 122         this.debug = lirGenRes.getLIR().getDebug();
 123         this.lirGenRes = lirGenRes;
 124         this.spillMoveFactory = spillMoveFactory;
 125         this.registerAllocationConfig = registerAllocationConfig;
 126         this.callerSaveRegs = registerAllocationConfig.getRegisterConfig().getCallerSaveRegisters();
 127         this.registerAttributes = registerAllocationConfig.getRegisterConfig().getAttributesMap();
 128         this.allocatedBlocks = new BitSet(lirGenRes.getLIR().getControlFlowGraph().getBlocks().length);
 129         this.resultTraces = resultTraces;
 130         this.moveResolver = new TraceGlobalMoveResolver(lirGenRes, spillMoveFactory, registerAllocationConfig, target.arch);
 131         this.neverSpillConstants = neverSpillConstant;
 132         this.livenessInfo = livenessInfo;
 133 
 134         this.insertInstructionsBefore = new ArrayList<>(4);
 135         this.insertInstructionsAfter = new ArrayList<>(4);
 136 
 137         if (TraceRegisterAllocationPhase.Options.TraceRACacheStackSlots.getValue(lirGenRes.getLIR().getOptions())) {
 138             this.stackSlots = cachedStackSlots;
 139         } else {
 140             this.stackSlots = new AllocatableValue[lirGenRes.getLIR().numVariables()];
 141         }
 142 
 143     }
 144 
 145     private LIR getLIR() {
 146         return lirGenRes.getLIR();
 147     }
 148 
 149     /**
 150      * Gets an object describing the attributes of a given register according to this register
 151      * configuration.
 152      */
 153     private RegisterAttributes attributes(Register reg) {
 154         return registerAttributes[reg.number];
 155     }
 156 
 157     /**
 158      * Returns a new spill slot or a cached entry if there is already one for the variable.
 159      */
 160     private AllocatableValue allocateSpillSlot(Variable var) {
 161         int variableIndex = var.index;
 162         AllocatableValue cachedStackSlot = stackSlots[variableIndex];
 163         if (cachedStackSlot != null) {
 164             TraceRegisterAllocationPhase.globalStackSlots.increment(debug);
 165             assert cachedStackSlot.getValueKind().equals(var.getValueKind()) : "CachedStackSlot: kind mismatch? " + var.getValueKind() + " vs. " + cachedStackSlot.getValueKind();
 166             return cachedStackSlot;
 167         }
 168         VirtualStackSlot slot = lirGenRes.getFrameMapBuilder().allocateSpillSlot(var.getValueKind());
 169         stackSlots[variableIndex] = slot;
 170         TraceRegisterAllocationPhase.allocatedStackSlots.increment(debug);
 171         return slot;
 172     }
 173 
 174     @Override
 175     protected void run(@SuppressWarnings("hiding") TargetDescription target, @SuppressWarnings("hiding") LIRGenerationResult lirGenRes, Trace trace, TraceAllocationContext context) {
 176         allocate(trace);
 177     }
 178 
 179     private void allocate(Trace trace) {
 180         if (neverSpillConstants) {
 181             throw JVMCIError.unimplemented("NeverSpillConstant not supported!");
 182         }
 183         new Allocator().allocateTrace(trace);
 184         assert verify(trace);
 185     }
 186 
 187     private boolean verify(Trace trace) {
 188         for (AbstractBlockBase<?> block : trace.getBlocks()) {
 189             assert LIR.verifyBlock(lirGenRes.getLIR(), block);
 190         }
 191         return true;
 192     }
 193 
 194     private static boolean requiresRegisters(LIRInstruction instruction, Value value, OperandMode mode, EnumSet<OperandFlag> flags) {
 195         assert isVariable(value) : "Not a variable " + value;
 196         if (instruction instanceof LabelOp) {
 197             // phi and incoming values do not require a register
 198             return false;
 199         }
 200         if (mode == OperandMode.DEF || mode == OperandMode.TEMP) {
 201             return true;
 202         }
 203         return !flags.contains(OperandFlag.STACK);
 204     }
 205 
 206     private void resolveFindInsertPos(AbstractBlockBase<?> fromBlock, AbstractBlockBase<?> toBlock) {
 207         LIR lir = lirGenRes.getLIR();
 208         if (fromBlock.getSuccessorCount() <= 1) {
 209             if (debug.isLogEnabled()) {
 210                 debug.log("inserting moves at end of fromBlock B%d", fromBlock.getId());
 211             }
 212 
 213             ArrayList<LIRInstruction> instructions = lir.getLIRforBlock(fromBlock);
 214             LIRInstruction instr = instructions.get(instructions.size() - 1);
 215             if (instr instanceof StandardOp.JumpOp) {
 216                 // insert moves before branch
 217                 moveResolver.setInsertPosition(instructions, instructions.size() - 1);
 218             } else {
 219                 moveResolver.setInsertPosition(instructions, instructions.size());
 220             }
 221 
 222         } else {
 223             if (debug.isLogEnabled()) {
 224                 debug.log("inserting moves at beginning of toBlock B%d", toBlock.getId());
 225             }
 226 
 227             if (DetailedAsserts.getValue(getLIR().getOptions())) {
 228                 assert lir.getLIRforBlock(fromBlock).get(0) instanceof StandardOp.LabelOp : "block does not start with a label";
 229 
 230                 /*
 231                  * Because the number of predecessor edges matches the number of successor edges,
 232                  * blocks which are reached by switch statements may have be more than one
 233                  * predecessor but it will be guaranteed that all predecessors will be the same.
 234                  */
 235                 for (AbstractBlockBase<?> predecessor : toBlock.getPredecessors()) {
 236                     assert fromBlock == predecessor : "all critical edges must be broken";
 237                 }
 238             }
 239 
 240             moveResolver.setInsertPosition(lir.getLIRforBlock(toBlock), 1);
 241         }
 242     }
 243 
 244     private final class Allocator {
 245 
 246         /**
 247          * Maps from {@linkplain Register#number register} to the current {@linkplain Variable
 248          * variable}.
 249          */
 250         private final AllocatableValue[] currentRegisterMapping;
 251         /**
 252          * Maps from {@linkplain Variable#index variable} to its current location.
 253          */
 254         private final AllocatableValue[] locations;
 255 
 256         private final int[] lastRegisterUsage;
 257         private final int[] lastRegisterKill;
 258 
 259         private ArrayList<LIRInstruction> currentInstructions;
 260         private int currentInstructionIndex;
 261         private int currentOpId;
 262 
 263         private Allocator() {
 264             RegisterArray registers = target.arch.getRegisters();
 265             int numRegs = registers.size();
 266             int numVar = getLIR().numVariables();
 267             currentRegisterMapping = new AllocatableValue[numRegs];
 268             lastRegisterUsage = new int[numRegs];
 269             lastRegisterKill = new int[numRegs];
 270             locations = new AllocatableValue[numVar];
 271             // we start at offset 2 to distinguish if from the default value
 272             currentOpId = 2;
 273         }
 274 
 275         private void setCurrentValue(Register reg, AllocatableValue val) {
 276             currentRegisterMapping[reg.number] = val;
 277         }
 278 
 279         private AllocatableValue getCurrentValue(Register reg) {
 280             return currentRegisterMapping[reg.number];
 281         }
 282 
 283         private int getLastRegisterUsage(Register reg) {
 284             return lastRegisterUsage[reg.number];
 285         }
 286 
 287         private void setLastRegisterUsage(Register reg, int pos) {
 288             debug.log("Register %s last used %d", reg, pos);
 289             lastRegisterUsage[reg.number] = pos;
 290         }
 291 
 292         private int getLastRegisterKill(Register reg) {
 293             return lastRegisterKill[reg.number];
 294         }
 295 
 296         private void setLastRegisterKill(Register reg, int pos) {
 297             debug.log("Register %s killed %d", reg, pos);
 298             lastRegisterKill[reg.number] = pos;
 299         }
 300 
 301         private void setCurrentLocation(Variable var, AllocatableValue location) {
 302             locations[var.index] = location;
 303         }
 304 
 305         private AllocatableValue getCurrentLocation(Variable var) {
 306             return locations[var.index];
 307         }
 308 
 309         private void insertSpillMoveBefore(AllocatableValue dst, Value src) {
 310             LIRInstruction move = spillMoveFactory.createMove(dst, src);
 311             insertInstructionsBefore.add(move);
 312             move.setComment(lirGenRes, "BottomUp: spill move before");
 313             debug.log("insert before %s", move);
 314         }
 315 
 316         private void insertSpillMoveAfter(AllocatableValue dst, Value src) {
 317             LIRInstruction inst = currentInstructions.get(currentInstructionIndex);
 318             if (!(inst instanceof BlockEndOp)) {
 319                 LIRInstruction move = spillMoveFactory.createMove(dst, src);
 320                 insertInstructionsAfter.add(move);
 321                 move.setComment(lirGenRes, "BottomUp: spill move after");
 322                 debug.log("insert after %s", move);
 323             } else {
 324                 debug.log("Block end op. No from %s to %s necessary.", src, dst);
 325                 requireResolution = true;
 326             }
 327         }
 328 
 329         private void insertInstructions() {
 330             // TODO (je) this is can probably be improved
 331             currentInstructions.ensureCapacity(currentInstructions.size() + insertInstructionsBefore.size() + insertInstructionsAfter.size());
 332             LIRInstruction inst = currentInstructions.get(currentInstructionIndex);
 333             // insert after
 334             if (insertInstructionsAfter.size() != 0) {
 335                 Collections.reverse(insertInstructionsAfter);
 336                 assert !(inst instanceof BlockEndOp) : "Cannot insert instruction after the block end op: " + inst;
 337                 currentInstructions.addAll(currentInstructionIndex + 1, insertInstructionsAfter);
 338                 insertInstructionsAfter.clear();
 339             }
 340             // insert before
 341             if (insertInstructionsBefore.size() != 0) {
 342                 assert !(inst instanceof LabelOp) : "Cannot insert instruction before the label op: " + inst;
 343                 currentInstructions.addAll(currentInstructionIndex, insertInstructionsBefore);
 344                 insertInstructionsBefore.clear();
 345             }
 346         }
 347 
 348         @SuppressWarnings("try")
 349         private void allocateTrace(Trace trace) {
 350             try (DebugContext.Scope s = debug.scope("BottomUpAllocator", trace.getBlocks()); Indent indent = debug.logAndIndent("%s (Trace%d)", trace, trace.getId())) {
 351                 AbstractBlockBase<?>[] blocks = trace.getBlocks();
 352                 int lastBlockIdx = blocks.length - 1;
 353                 AbstractBlockBase<?> successorBlock = blocks[lastBlockIdx];
 354                 // handle last block
 355                 allocateBlock(successorBlock);
 356                 // handle remaining blocks
 357                 for (int i = lastBlockIdx - 1; i >= 0; i--) {
 358                     AbstractBlockBase<?> block = blocks[i];
 359                     // handle PHIs
 360                     resolvePhis(block, successorBlock);
 361                     boolean needResolution = allocateBlock(block);
 362 
 363                     if (needResolution) {
 364                         // resolve local data flow
 365                         resolveIntraTraceEdge(block, successorBlock);
 366                     }
 367                     successorBlock = block;
 368                 }
 369                 resolveLoopBackEdge(trace);
 370             } catch (Throwable e) {
 371                 throw debug.handle(e);
 372             }
 373         }
 374 
 375         private final ArrayList<LIRInstruction> phiResolutionMoves = new ArrayList<>();
 376 
 377         /**
 378          * Resolve phi values, i.e., set the current location of values in the predecessors block
 379          * (which is not yet allocated) to the location of the variable defined by the phi in the
 380          * successor (which is already allocated). For constant inputs we insert moves.
 381          */
 382         private void resolvePhis(AbstractBlockBase<?> from, AbstractBlockBase<?> to) {
 383             if (SSAUtil.isMerge(to)) {
 384                 JumpOp jump = SSAUtil.phiOut(getLIR(), from);
 385                 LabelOp label = SSAUtil.phiIn(getLIR(), to);
 386 
 387                 assert phiResolutionMoves.isEmpty();
 388 
 389                 for (int i = 0; i < label.getPhiSize(); i++) {
 390                     visitPhiValuePair(jump.getOutgoingValue(i), label.getIncomingValue(i));
 391                 }
 392                 if (!phiResolutionMoves.isEmpty()) {
 393                     ArrayList<LIRInstruction> instructions = getLIR().getLIRforBlock(from);
 394                     instructions.addAll(instructions.size() - 1, phiResolutionMoves);
 395                     phiResolutionMoves.clear();
 396                 }
 397             }
 398         }
 399 
 400         private void visitPhiValuePair(Value phiOut, Value phiIn) {
 401             assert isStackSlotValue(phiIn) || isRegister(phiIn) : "PHI defined values is not a register or stack slot: " + phiIn;
 402             AllocatableValue in = asAllocatableValue(phiIn);
 403 
 404             AllocatableValue dest = isRegister(in) ? getCurrentValue(asRegister(in)) : in;
 405             final LIRInstruction move;
 406             if (isConstantValue(phiOut)) {
 407                 // insert move from constant
 408                 move = spillMoveFactory.createLoad(dest, LIRValueUtil.asConstant(phiOut));
 409             } else {
 410                 assert isVariable(phiOut) : "Not a variable or constant: " + phiOut;
 411                 // insert move from variable
 412                 move = spillMoveFactory.createMove(dest, asVariable(phiOut));
 413             }
 414             debug.log("Inserting load %s", move);
 415             move.setComment(lirGenRes, "BottomUp: phi resolution");
 416             phiResolutionMoves.add(move);
 417         }
 418 
 419         private boolean requireResolution;
 420 
 421         /**
 422          * Intra-trace edges, i.e., edge where both, the source and the target block are in the same
 423          * trace, are either
 424          * <ul>
 425          * <li><em>immediate forward edges</em>, i.e., an edge from {@code i}th block of the trace
 426          * to the {@code (i+1)}th block, or
 427          * <li>a <em>loop back-edge</em> from the last block of the trace to the loop header.
 428          * </ul>
 429          * This property is guaranteed due to splitting of <em>critical edge</em>.
 430          *
 431          * Since forward edges are handled locally during bottom-up allocation we only need to check
 432          * for the second case.
 433          */
 434         private void resolveLoopBackEdge(Trace trace) {
 435             AbstractBlockBase<?>[] blocks = trace.getBlocks();
 436             AbstractBlockBase<?> endBlock = blocks[blocks.length - 1];
 437             if (endBlock.isLoopEnd()) {
 438                 assert endBlock.getSuccessorCount() == 1;
 439                 AbstractBlockBase<?> targetBlock = endBlock.getSuccessors()[0];
 440                 assert targetBlock.isLoopHeader() : String.format("Successor %s or loop end %s is not a loop header?", targetBlock, endBlock);
 441                 if (resultTraces.getTraceForBlock(targetBlock).equals(trace)) {
 442                     resolveLoopBackEdge(endBlock, targetBlock);
 443                 }
 444             }
 445         }
 446 
 447         private void resolveLoopBackEdge(AbstractBlockBase<?> from, AbstractBlockBase<?> to) {
 448             assert resultTraces.getTraceForBlock(from).equals(resultTraces.getTraceForBlock(to)) : "Not on the same trace? " + from + " -> " + to;
 449             resolveFindInsertPos(from, to);
 450             LIR lir = getLIR();
 451 
 452             if (SSAUtil.isMerge(to)) {
 453                 JumpOp blockEnd = SSAUtil.phiOut(lir, from);
 454                 LabelOp label = SSAUtil.phiIn(lir, to);
 455 
 456                 for (int i = 0; i < label.getPhiSize(); i++) {
 457                     Value incomingValue = label.getIncomingValue(i);
 458                     Value outgoingValue = blockEnd.getOutgoingValue(i);
 459                     resolveValuePair(incomingValue, outgoingValue);
 460                 }
 461             }
 462             resolveTraceEdge(from, to);
 463             moveResolver.resolveAndAppendMoves();
 464         }
 465 
 466         private void resolveIntraTraceEdge(AbstractBlockBase<?> from, AbstractBlockBase<?> to) {
 467             assert resultTraces.getTraceForBlock(from).equals(resultTraces.getTraceForBlock(to)) : "Not on the same trace? " + from + " -> " + to;
 468             resolveFindInsertPos(from, to);
 469             resolveTraceEdge(from, to);
 470             moveResolver.resolveAndAppendMoves();
 471         }
 472 
 473         private void resolveTraceEdge(AbstractBlockBase<?> from, AbstractBlockBase<?> to) {
 474             Value[] out = livenessInfo.getOutLocation(from);
 475             Value[] in = livenessInfo.getInLocation(to);
 476 
 477             assert out != null;
 478             assert in != null;
 479             assert out.length == in.length;
 480 
 481             for (int i = 0; i < out.length; i++) {
 482                 Value incomingValue = in[i];
 483                 Value outgoingValue = out[i];
 484                 resolveValuePair(incomingValue, outgoingValue);
 485             }
 486         }
 487 
 488         private void resolveValuePair(Value incomingValue, Value outgoingValue) {
 489             if (!isIllegal(incomingValue) && !TraceGlobalMoveResolver.isMoveToSelf(outgoingValue, incomingValue)) {
 490                 TraceGlobalMoveResolutionPhase.addMapping(moveResolver, outgoingValue, incomingValue);
 491             }
 492         }
 493 
 494         /**
 495          * @return {@code true} if the block requires data-flow resolution.
 496          */
 497         @SuppressWarnings("try")
 498         private boolean allocateBlock(AbstractBlockBase<?> block) {
 499             // might be set in insertSpillMoveAfter
 500             requireResolution = false;
 501 
 502             try (Indent indent = debug.logAndIndent("handle block %s", block)) {
 503                 currentInstructions = getLIR().getLIRforBlock(block);
 504                 for (currentInstructionIndex = currentInstructions.size() - 1; currentInstructionIndex >= 0; currentInstructionIndex--) {
 505                     LIRInstruction inst = currentInstructions.get(currentInstructionIndex);
 506                     if (inst != null) {
 507                         inst.setId(currentOpId);
 508                         allocateInstruction(inst, block);
 509                     }
 510                 }
 511                 allocatedBlocks.set(block.getId());
 512             }
 513             return requireResolution;
 514         }
 515 
 516         @SuppressWarnings("try")
 517         private void allocateInstruction(LIRInstruction op, AbstractBlockBase<?> block) {
 518             assert op != null && op.id() == currentOpId;
 519             try (Indent indent = debug.logAndIndent("handle inst: %d: %s", op.id(), op)) {
 520                 try (Indent indent1 = debug.logAndIndent("output pos")) {
 521                     // spill caller saved registers
 522                     if (op.destroysCallerSavedRegisters()) {
 523                         spillCallerSavedRegisters();
 524                     }
 525 
 526                     // fixed
 527                     op.forEachOutput(allocFixedRegisterProcedure);
 528                     op.forEachTemp(allocFixedRegisterProcedure);
 529                     op.forEachAlive(allocFixedRegisterProcedure);
 530                     // variable
 531                     op.forEachOutput(allocRegisterProcedure);
 532                     op.forEachTemp(allocRegisterProcedure);
 533                     op.forEachAlive(allocRegisterProcedure);
 534                     /* state do never require a register */
 535                     // op.forEachState(allocRegisterProcedure);
 536 
 537                     // should have
 538                     op.forEachTemp(allocStackOrRegisterProcedure);
 539                     op.forEachOutput(allocStackOrRegisterProcedure);
 540                     if (op instanceof LabelOp) {
 541                         processIncoming(block, op);
 542                     }
 543                 }
 544                 try (Indent indent1 = debug.logAndIndent("input pos")) {
 545 
 546                     currentOpId++;
 547 
 548                     // fixed
 549                     op.forEachInput(allocFixedRegisterProcedure);
 550                     // variable
 551                     op.forEachInput(allocRegisterProcedure);
 552 
 553                     op.forEachAlive(allocStackOrRegisterProcedure);
 554                     if (op instanceof BlockEndOp) {
 555                         processOutgoing(block, op);
 556                     }
 557                     op.forEachState(allocStackOrRegisterProcedure);
 558                     op.forEachInput(allocStackOrRegisterProcedure);
 559                 }
 560 
 561                 // insert spill/load instructions
 562                 insertInstructions();
 563                 currentOpId++;
 564             }
 565         }
 566 
 567         private void processIncoming(AbstractBlockBase<?> block, LIRInstruction instruction) {
 568             int[] vars = livenessInfo.getBlockIn(block);
 569             Value[] locs = new Value[vars.length];
 570             for (int i = 0; i < vars.length; i++) {
 571                 int varNum = vars[i];
 572                 if (varNum >= 0) {
 573                     locs[i] = allocStackOrRegister(instruction, livenessInfo.getVariable(varNum), OperandMode.DEF, LabelOp.incomingFlags);
 574                 }
 575             }
 576             livenessInfo.setInLocations(block, locs);
 577         }
 578 
 579         private void processOutgoing(AbstractBlockBase<?> block, LIRInstruction instruction) {
 580             int[] vars = livenessInfo.getBlockOut(block);
 581             Value[] locs = new Value[vars.length];
 582             for (int i = 0; i < vars.length; i++) {
 583                 locs[i] = allocStackOrRegister(instruction, livenessInfo.getVariable(vars[i]), OperandMode.ALIVE, JumpOp.outgoingFlags);
 584             }
 585             livenessInfo.setOutLocations(block, locs);
 586         }
 587 
 588         private void spillCallerSavedRegisters() {
 589             for (Register reg : callerSaveRegs) {
 590                 if (attributes(reg).isAllocatable()) {
 591                     evacuateRegisterAndSpill(reg);
 592                     assert checkRegisterUsage(reg);
 593                     setLastRegisterUsage(reg, currentOpId);
 594                 }
 595             }
 596             if (debug.isLogEnabled()) {
 597                 debug.log("operation destroys all caller-save registers");
 598             }
 599         }
 600 
 601         private final InstructionValueProcedure allocFixedRegisterProcedure = new InstructionValueProcedure() {
 602             @Override
 603             public Value doValue(LIRInstruction instruction, Value value, OperandMode mode, EnumSet<OperandFlag> flags) {
 604                 return allocFixedRegister(value);
 605             }
 606         };
 607         private final InstructionValueProcedure allocRegisterProcedure = new InstructionValueProcedure() {
 608             @Override
 609             public Value doValue(LIRInstruction instruction, Value value, OperandMode mode, EnumSet<OperandFlag> flags) {
 610                 return allocRegister(instruction, value, mode, flags);
 611             }
 612         };
 613         private final InstructionValueProcedure allocStackOrRegisterProcedure = new InstructionValueProcedure() {
 614             @Override
 615             public Value doValue(LIRInstruction instruction, Value value, OperandMode mode, EnumSet<OperandFlag> flags) {
 616                 return allocStackOrRegister(instruction, value, mode, flags);
 617             }
 618         };
 619 
 620         private Value allocFixedRegister(Value value) {
 621             if (isRegister(value)) {
 622                 Register reg = asRegister(value);
 623                 assert checkRegisterUsage(reg);
 624                 evacuateRegisterAndSpill(reg);
 625                 setRegisterUsage(reg, asAllocatableValue(value));
 626             }
 627             return value;
 628         }
 629 
 630         private Value allocRegister(LIRInstruction instruction, Value value, OperandMode mode, EnumSet<OperandFlag> flags) {
 631             if (isVariable(value) && requiresRegisters(instruction, value, mode, flags)) {
 632                 Variable var = asVariable(value);
 633                 // check if available
 634                 AllocatableValue currentLocation = getCurrentLocation(var);
 635                 if (currentLocation == null) {
 636                     // nothing yet assigned
 637                     return allocRegister(var, mode);
 638                 }
 639                 // already a location assigned
 640                 if (isRegister(currentLocation)) {
 641                     // register assigned -> nothing todo
 642                     setLastRegisterUsage(asRegister(currentLocation), currentOpId);
 643                     return currentLocation;
 644                 }
 645                 assert isStackSlotValue(currentLocation);
 646                 // stackSlot assigned but need register -> spill
 647                 Value allocatedRegister = allocRegister(var, mode);
 648                 if (mode == OperandMode.USE) {
 649                     // input might be destroyed at the def position
 650                     // but it must be available before the instruction
 651                     insertSpillMoveBefore(currentLocation, allocatedRegister);
 652                 } else {
 653                     insertSpillMoveAfter(currentLocation, allocatedRegister);
 654                 }
 655                 return allocatedRegister;
 656             }
 657             return value;
 658         }
 659 
 660         private Value allocRegister(Variable var, OperandMode mode) {
 661             PlatformKind platformKind = var.getPlatformKind();
 662             Register freeRegister = findFreeRegister(platformKind, mode);
 663             if (freeRegister == null) {
 664                 // no free register found, looking for a blocked one
 665                 freeRegister = findLockedRegister(platformKind, mode);
 666                 if (freeRegister == null) {
 667                     throw new OutOfRegistersException("TraceRA[BottomUp]: no register found");
 668                 }
 669             }
 670             // found a register
 671             setRegisterUsage(freeRegister, var);
 672             RegisterValue registerValue = freeRegister.asValue(var.getValueKind());
 673             setCurrentLocation(var, registerValue);
 674             debug.log("AllocateRegister[%5s] %s for %s", mode, freeRegister, var);
 675             return registerValue;
 676         }
 677 
 678         private Value allocStackOrRegister(LIRInstruction instruction, Value value, OperandMode mode, EnumSet<OperandFlag> flags) {
 679             if (isRegister(value)) {
 680                 if ((mode == OperandMode.DEF || mode == OperandMode.TEMP) && !(instruction instanceof LabelOp)) {
 681                     freeRegister(asRegister(value));
 682                 }
 683                 return value;
 684             }
 685             if (isVariable(value)) {
 686                 assert !requiresRegisters(instruction, value, mode, flags) : "Should have a register already: " + value;
 687                 Variable var = asVariable(value);
 688                 // check if available
 689                 AllocatableValue currentLocation = getCurrentLocation(var);
 690                 if (currentLocation != null) {
 691                     // already a location assigned -> nothing todo
 692                     if (isRegister(currentLocation)) {
 693                         Register reg = asRegister(currentLocation);
 694                         if (mode == OperandMode.ALIVE && killedAtDef(reg)) {
 695                             AllocatableValue spillSlot = allocateSpillSlot(var);
 696                             insertSpillMoveBefore(spillSlot, currentLocation);
 697                             debug.log("AllocateStackOrReg[%5s] temporary use %s for %s since current location %s is destroyed at def", mode, spillSlot, var, currentLocation);
 698                             return spillSlot;
 699                         }
 700                         // update register usage
 701                         setLastRegisterUsage(reg, currentOpId);
 702                     }
 703                     debug.log(3, "AllocateStackOrReg[%5s] %s already in %s", mode, var, currentLocation);
 704                     return currentLocation;
 705                 }
 706                 // no location available
 707                 PlatformKind platformKind = var.getPlatformKind();
 708                 Register freeRegister = findFreeRegister(platformKind, mode);
 709                 if (freeRegister == null) {
 710                     // no free register available -> either spill current or free a register
 711                     AllocatableValue spillSlot = allocateSpillSlot(var);
 712                     setCurrentLocation(var, spillSlot);
 713                     return spillSlot;
 714                 }
 715                 assert freeRegister != null;
 716                 // found a register
 717                 setRegisterUsage(freeRegister, var);
 718                 RegisterValue registerValue = freeRegister.asValue(var.getValueKind());
 719                 setCurrentLocation(var, registerValue);
 720                 debug.log("AllocateStackOrReg[%5s] %s for %s", mode, freeRegister, var);
 721                 return registerValue;
 722             }
 723             return value;
 724         }
 725 
 726         private boolean killedAtDef(Register reg) {
 727             return getLastRegisterKill(reg) == currentOpId - 1;
 728         }
 729 
 730         /**
 731          * Searches for a free register.
 732          */
 733         @SuppressWarnings("try")
 734         private Register findFreeRegister(PlatformKind kind, OperandMode mode) {
 735             AllocatableRegisters allocatableRegisters = registerAllocationConfig.getAllocatableRegisters(kind);
 736             Register[] availableRegs = allocatableRegisters.allocatableRegisters;
 737             for (Register reg : availableRegs) {
 738                 AllocatableValue currentVal = getCurrentValue(reg);
 739                 if (currentVal == null && !isCurrentlyUsed(reg, mode)) {
 740                     return reg;
 741                 }
 742             }
 743             if (debug.isLogEnabled()) {
 744                 try (Indent i = debug.logAndIndent("All Registers occupied:")) {
 745                     for (Register reg : availableRegs) {
 746                         debug.log("%6s: last used %4d %s", reg, getLastRegisterUsage(reg), getCurrentValue(reg));
 747                     }
 748                 }
 749             }
 750             return null;
 751         }
 752 
 753         /**
 754          * Searches for a occupied register to spill.
 755          */
 756         @SuppressWarnings("try")
 757         private Register findLockedRegister(PlatformKind kind, OperandMode mode) {
 758             AllocatableRegisters allocatableRegisters = registerAllocationConfig.getAllocatableRegisters(kind);
 759             Register[] availableRegs = allocatableRegisters.allocatableRegisters;
 760             // TODO (je): better strategies for spilling
 761             // TODO (je): we need to ensure that we do not use the register in the current
 762             // instruction!
 763             Register lockedReg = null;
 764             for (Register reg : availableRegs) {
 765                 if (!isCurrentlyUsed(reg, mode) && !isActiveFixedRegister(reg)) {
 766                     lockedReg = reg;
 767                     break;
 768                 }
 769             }
 770             if (lockedReg == null) {
 771                 return null;
 772             }
 773             evacuateRegisterAndSpill(lockedReg);
 774             return lockedReg;
 775         }
 776 
 777         private boolean isActiveFixedRegister(Register reg) {
 778             return isRegister(getCurrentValue(reg));
 779         }
 780 
 781         private boolean isCurrentlyUsed(Register reg, OperandMode mode) {
 782             int lastRegUsage = getLastRegisterUsage(reg);
 783             if (lastRegUsage == currentOpId) {
 784                 return true;
 785             }
 786             return mode == OperandMode.ALIVE && lastRegUsage == (currentOpId & ~1);
 787         }
 788 
 789         private void freeRegister(Register reg) {
 790             AllocatableValue val = getCurrentValue(reg);
 791             setCurrentValue(reg, null);
 792             setLastRegisterKill(reg, currentOpId);
 793             if (val != null && isVariable(val)) {
 794                 Variable var = asVariable(val);
 795                 setCurrentLocation(var, null);
 796                 debug.log("Free Registers %s (was %s)", reg, var);
 797             } else {
 798                 debug.log("Free Registers %s", reg);
 799             }
 800         }
 801 
 802         private void setRegisterUsage(Register reg, AllocatableValue currentValue) {
 803             assert checkRegisterUsage(reg);
 804             setCurrentValue(reg, currentValue);
 805             setLastRegisterUsage(reg, currentOpId);
 806         }
 807 
 808         private boolean checkRegisterUsage(Register reg) {
 809             AllocatableValue currentValue = getCurrentValue(reg);
 810             assert getLastRegisterUsage(reg) < currentOpId || currentValue == null || isRegister(currentValue) && asRegister(currentValue).equals(reg) : String.format("Register %s is occupied", reg);
 811             return true;
 812         }
 813 
 814         /**
 815          * Frees a registers and spill the variable that is currently occupying it.
 816          *
 817          * @return The value that currently occupies the register or {@code null} if there is none.
 818          */
 819         private AllocatableValue evacuateRegisterAndSpill(Register reg) {
 820             AllocatableValue val = evacuateRegister(reg);
 821             spillVariable(val, reg);
 822             return val;
 823         }
 824 
 825         /**
 826          * Frees a registers. The variable that is currently occupying it is <em>not</em> spilled.
 827          *
 828          * @return The value that currently occupies the register or {@code null} if there is none.
 829          */
 830         private AllocatableValue evacuateRegister(Register reg) {
 831             AllocatableValue val = getCurrentValue(reg);
 832             if (val == null) {
 833                 return null;
 834             }
 835             setCurrentValue(reg, null);
 836             return val;
 837         }
 838 
 839         private void spillVariable(AllocatableValue val, Register reg) {
 840             if (val != null && isVariable(val)) {
 841                 Variable var = asVariable(val);
 842                 debug.log("Spill Variable %s from %s", var, reg);
 843                 // insert reload
 844                 AllocatableValue spillSlot = allocateSpillSlot(var);
 845                 setCurrentLocation(var, spillSlot);
 846                 insertSpillMoveAfter(reg.asValue(var.getValueKind()), spillSlot);
 847             }
 848         }
 849     }
 850 }