001/* 002 * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved. 003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 004 * 005 * This code is free software; you can redistribute it and/or modify it 006 * under the terms of the GNU General Public License version 2 only, as 007 * published by the Free Software Foundation. 008 * 009 * This code is distributed in the hope that it will be useful, but WITHOUT 010 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 011 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 012 * version 2 for more details (a copy is included in the LICENSE file that 013 * accompanied this code). 014 * 015 * You should have received a copy of the GNU General Public License version 016 * 2 along with this work; if not, write to the Free Software Foundation, 017 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 018 * 019 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 020 * or visit www.oracle.com if you need additional information or have any 021 * questions. 022 */ 023package com.oracle.graal.lir.alloc.lsra; 024 025import static com.oracle.graal.compiler.common.GraalOptions.*; 026import static com.oracle.graal.lir.LIRValueUtil.*; 027import static com.oracle.graal.lir.debug.LIRGenerationDebugContext.*; 028import static jdk.internal.jvmci.code.ValueUtil.*; 029 030import java.util.*; 031 032import jdk.internal.jvmci.code.*; 033import jdk.internal.jvmci.common.*; 034import com.oracle.graal.debug.*; 035import com.oracle.graal.debug.Debug.*; 036import jdk.internal.jvmci.meta.*; 037 038import com.oracle.graal.compiler.common.alloc.*; 039import com.oracle.graal.compiler.common.cfg.*; 040import com.oracle.graal.compiler.common.util.*; 041import com.oracle.graal.lir.*; 042import com.oracle.graal.lir.LIRInstruction.OperandFlag; 043import com.oracle.graal.lir.LIRInstruction.OperandMode; 044import com.oracle.graal.lir.StandardOp.MoveOp; 045import com.oracle.graal.lir.StandardOp.StackStoreOp; 046import com.oracle.graal.lir.alloc.lsra.Interval.RegisterPriority; 047import com.oracle.graal.lir.alloc.lsra.Interval.SpillState; 048import com.oracle.graal.lir.alloc.lsra.LinearScan.BlockData; 049import com.oracle.graal.lir.gen.*; 050import com.oracle.graal.lir.gen.LIRGeneratorTool.SpillMoveFactory; 051import com.oracle.graal.lir.phases.*; 052 053public class LinearScanLifetimeAnalysisPhase extends AllocationPhase { 054 055 protected final LinearScan allocator; 056 057 /** 058 * @param linearScan 059 */ 060 protected LinearScanLifetimeAnalysisPhase(LinearScan linearScan) { 061 allocator = linearScan; 062 } 063 064 @Override 065 protected <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, SpillMoveFactory spillMoveFactory, 066 RegisterAllocationConfig registerAllocationConfig) { 067 numberInstructions(); 068 allocator.printLir("Before register allocation", true); 069 computeLocalLiveSets(); 070 computeGlobalLiveSets(); 071 buildIntervals(); 072 } 073 074 /** 075 * Bit set for each variable that is contained in each loop. 076 */ 077 private BitMap2D intervalInLoop; 078 079 boolean isIntervalInLoop(int interval, int loop) { 080 return intervalInLoop.at(interval, loop); 081 } 082 083 /** 084 * Numbers all instructions in all blocks. The numbering follows the 085 * {@linkplain ComputeBlockOrder linear scan order}. 086 */ 087 protected void numberInstructions() { 088 089 allocator.initIntervals(); 090 091 ValueConsumer setVariableConsumer = (value, mode, flags) -> { 092 if (isVariable(value)) { 093 allocator.getOrCreateInterval(asVariable(value)); 094 } 095 }; 096 097 // Assign IDs to LIR nodes and build a mapping, lirOps, from ID to LIRInstruction node. 098 int numInstructions = 0; 099 for (AbstractBlockBase<?> block : allocator.sortedBlocks()) { 100 numInstructions += allocator.getLIR().getLIRforBlock(block).size(); 101 } 102 103 // initialize with correct length 104 allocator.initOpIdMaps(numInstructions); 105 106 int opId = 0; 107 int index = 0; 108 for (AbstractBlockBase<?> block : allocator.sortedBlocks()) { 109 allocator.initBlockData(block); 110 111 List<LIRInstruction> instructions = allocator.getLIR().getLIRforBlock(block); 112 113 int numInst = instructions.size(); 114 for (int j = 0; j < numInst; j++) { 115 LIRInstruction op = instructions.get(j); 116 op.setId(opId); 117 118 allocator.putOpIdMaps(index, op, block); 119 assert allocator.instructionForId(opId) == op : "must match"; 120 121 op.visitEachTemp(setVariableConsumer); 122 op.visitEachOutput(setVariableConsumer); 123 124 index++; 125 opId += 2; // numbering of lirOps by two 126 } 127 } 128 assert index == numInstructions : "must match"; 129 assert (index << 1) == opId : "must match: " + (index << 1); 130 } 131 132 /** 133 * Computes local live sets (i.e. {@link BlockData#liveGen} and {@link BlockData#liveKill}) 134 * separately for each block. 135 */ 136 void computeLocalLiveSets() { 137 int liveSize = allocator.liveSetSize(); 138 139 intervalInLoop = new BitMap2D(allocator.operandSize(), allocator.numLoops()); 140 141 // iterate all blocks 142 for (final AbstractBlockBase<?> block : allocator.sortedBlocks()) { 143 try (Indent indent = Debug.logAndIndent("compute local live sets for block %s", block)) { 144 145 final BitSet liveGen = new BitSet(liveSize); 146 final BitSet liveKill = new BitSet(liveSize); 147 148 List<LIRInstruction> instructions = allocator.getLIR().getLIRforBlock(block); 149 int numInst = instructions.size(); 150 151 ValueConsumer useConsumer = (operand, mode, flags) -> { 152 if (isVariable(operand)) { 153 int operandNum = allocator.operandNumber(operand); 154 if (!liveKill.get(operandNum)) { 155 liveGen.set(operandNum); 156 if (Debug.isLogEnabled()) { 157 Debug.log("liveGen for operand %d(%s)", operandNum, operand); 158 } 159 } 160 if (block.getLoop() != null) { 161 intervalInLoop.setBit(operandNum, block.getLoop().getIndex()); 162 } 163 } 164 165 if (DetailedAsserts.getValue()) { 166 verifyInput(block, liveKill, operand); 167 } 168 }; 169 ValueConsumer stateConsumer = (operand, mode, flags) -> { 170 if (LinearScan.isVariableOrRegister(operand)) { 171 int operandNum = allocator.operandNumber(operand); 172 if (!liveKill.get(operandNum)) { 173 liveGen.set(operandNum); 174 if (Debug.isLogEnabled()) { 175 Debug.log("liveGen in state for operand %d(%s)", operandNum, operand); 176 } 177 } 178 } 179 }; 180 ValueConsumer defConsumer = (operand, mode, flags) -> { 181 if (isVariable(operand)) { 182 int varNum = allocator.operandNumber(operand); 183 liveKill.set(varNum); 184 if (Debug.isLogEnabled()) { 185 Debug.log("liveKill for operand %d(%s)", varNum, operand); 186 } 187 if (block.getLoop() != null) { 188 intervalInLoop.setBit(varNum, block.getLoop().getIndex()); 189 } 190 } 191 192 if (DetailedAsserts.getValue()) { 193 /* 194 * Fixed intervals are never live at block boundaries, so they need not be 195 * processed in live sets. Process them only in debug mode so that this can 196 * be checked 197 */ 198 verifyTemp(liveKill, operand); 199 } 200 }; 201 202 // iterate all instructions of the block 203 for (int j = 0; j < numInst; j++) { 204 final LIRInstruction op = instructions.get(j); 205 206 try (Indent indent2 = Debug.logAndIndent("handle op %d: %s", op.id(), op)) { 207 op.visitEachInput(useConsumer); 208 op.visitEachAlive(useConsumer); 209 /* 210 * Add uses of live locals from interpreter's point of view for proper debug 211 * information generation. 212 */ 213 op.visitEachState(stateConsumer); 214 op.visitEachTemp(defConsumer); 215 op.visitEachOutput(defConsumer); 216 } 217 } // end of instruction iteration 218 219 BlockData blockSets = allocator.getBlockData(block); 220 blockSets.liveGen = liveGen; 221 blockSets.liveKill = liveKill; 222 blockSets.liveIn = new BitSet(liveSize); 223 blockSets.liveOut = new BitSet(liveSize); 224 225 if (Debug.isLogEnabled()) { 226 Debug.log("liveGen B%d %s", block.getId(), blockSets.liveGen); 227 Debug.log("liveKill B%d %s", block.getId(), blockSets.liveKill); 228 } 229 230 } 231 } // end of block iteration 232 } 233 234 private void verifyTemp(BitSet liveKill, Value operand) { 235 /* 236 * Fixed intervals are never live at block boundaries, so they need not be processed in live 237 * sets. Process them only in debug mode so that this can be checked 238 */ 239 if (isRegister(operand)) { 240 if (allocator.isProcessed(operand)) { 241 liveKill.set(allocator.operandNumber(operand)); 242 } 243 } 244 } 245 246 private void verifyInput(AbstractBlockBase<?> block, BitSet liveKill, Value operand) { 247 /* 248 * Fixed intervals are never live at block boundaries, so they need not be processed in live 249 * sets. This is checked by these assertions to be sure about it. The entry block may have 250 * incoming values in registers, which is ok. 251 */ 252 if (isRegister(operand) && block != allocator.getLIR().getControlFlowGraph().getStartBlock()) { 253 if (allocator.isProcessed(operand)) { 254 assert liveKill.get(allocator.operandNumber(operand)) : "using fixed register that is not defined in this block"; 255 } 256 } 257 } 258 259 /** 260 * Performs a backward dataflow analysis to compute global live sets (i.e. 261 * {@link BlockData#liveIn} and {@link BlockData#liveOut}) for each block. 262 */ 263 protected void computeGlobalLiveSets() { 264 try (Indent indent = Debug.logAndIndent("compute global live sets")) { 265 int numBlocks = allocator.blockCount(); 266 boolean changeOccurred; 267 boolean changeOccurredInBlock; 268 int iterationCount = 0; 269 BitSet liveOut = new BitSet(allocator.liveSetSize()); // scratch set for calculations 270 271 /* 272 * Perform a backward dataflow analysis to compute liveOut and liveIn for each block. 273 * The loop is executed until a fixpoint is reached (no changes in an iteration). 274 */ 275 do { 276 changeOccurred = false; 277 278 try (Indent indent2 = Debug.logAndIndent("new iteration %d", iterationCount)) { 279 280 // iterate all blocks in reverse order 281 for (int i = numBlocks - 1; i >= 0; i--) { 282 AbstractBlockBase<?> block = allocator.blockAt(i); 283 BlockData blockSets = allocator.getBlockData(block); 284 285 changeOccurredInBlock = false; 286 287 /* liveOut(block) is the union of liveIn(sux), for successors sux of block. */ 288 int n = block.getSuccessorCount(); 289 if (n > 0) { 290 liveOut.clear(); 291 // block has successors 292 if (n > 0) { 293 for (AbstractBlockBase<?> successor : block.getSuccessors()) { 294 liveOut.or(allocator.getBlockData(successor).liveIn); 295 } 296 } 297 298 if (!blockSets.liveOut.equals(liveOut)) { 299 /* 300 * A change occurred. Swap the old and new live out sets to avoid 301 * copying. 302 */ 303 BitSet temp = blockSets.liveOut; 304 blockSets.liveOut = liveOut; 305 liveOut = temp; 306 307 changeOccurred = true; 308 changeOccurredInBlock = true; 309 } 310 } 311 312 if (iterationCount == 0 || changeOccurredInBlock) { 313 /* 314 * liveIn(block) is the union of liveGen(block) with (liveOut(block) & 315 * !liveKill(block)). 316 * 317 * Note: liveIn has to be computed only in first iteration or if liveOut 318 * has changed! 319 */ 320 BitSet liveIn = blockSets.liveIn; 321 liveIn.clear(); 322 liveIn.or(blockSets.liveOut); 323 liveIn.andNot(blockSets.liveKill); 324 liveIn.or(blockSets.liveGen); 325 326 if (Debug.isLogEnabled()) { 327 Debug.log("block %d: livein = %s, liveout = %s", block.getId(), liveIn, blockSets.liveOut); 328 } 329 } 330 } 331 iterationCount++; 332 333 if (changeOccurred && iterationCount > 50) { 334 throw new BailoutException("too many iterations in computeGlobalLiveSets"); 335 } 336 } 337 } while (changeOccurred); 338 339 if (DetailedAsserts.getValue()) { 340 verifyLiveness(); 341 } 342 343 // check that the liveIn set of the first block is empty 344 AbstractBlockBase<?> startBlock = allocator.getLIR().getControlFlowGraph().getStartBlock(); 345 if (allocator.getBlockData(startBlock).liveIn.cardinality() != 0) { 346 if (DetailedAsserts.getValue()) { 347 reportFailure(numBlocks); 348 } 349 // bailout if this occurs in product mode. 350 throw new JVMCIError("liveIn set of first block must be empty: " + allocator.getBlockData(startBlock).liveIn); 351 } 352 } 353 } 354 355 protected void reportFailure(int numBlocks) { 356 try (Scope s = Debug.forceLog()) { 357 try (Indent indent = Debug.logAndIndent("report failure")) { 358 359 BitSet startBlockLiveIn = allocator.getBlockData(allocator.getLIR().getControlFlowGraph().getStartBlock()).liveIn; 360 try (Indent indent2 = Debug.logAndIndent("Error: liveIn set of first block must be empty (when this fails, variables are used before they are defined):")) { 361 for (int operandNum = startBlockLiveIn.nextSetBit(0); operandNum >= 0; operandNum = startBlockLiveIn.nextSetBit(operandNum + 1)) { 362 Interval interval = allocator.intervalFor(operandNum); 363 if (interval != null) { 364 Value operand = interval.operand; 365 Debug.log("var %d; operand=%s; node=%s", operandNum, operand, getSourceForOperandFromDebugContext(operand)); 366 } else { 367 Debug.log("var %d; missing operand", operandNum); 368 } 369 } 370 } 371 372 // print some additional information to simplify debugging 373 for (int operandNum = startBlockLiveIn.nextSetBit(0); operandNum >= 0; operandNum = startBlockLiveIn.nextSetBit(operandNum + 1)) { 374 Interval interval = allocator.intervalFor(operandNum); 375 Value operand = null; 376 Object valueForOperandFromDebugContext = null; 377 if (interval != null) { 378 operand = interval.operand; 379 valueForOperandFromDebugContext = getSourceForOperandFromDebugContext(operand); 380 } 381 try (Indent indent2 = Debug.logAndIndent("---- Detailed information for var %d; operand=%s; node=%s ----", operandNum, operand, valueForOperandFromDebugContext)) { 382 383 Deque<AbstractBlockBase<?>> definedIn = new ArrayDeque<>(); 384 HashSet<AbstractBlockBase<?>> usedIn = new HashSet<>(); 385 for (AbstractBlockBase<?> block : allocator.sortedBlocks()) { 386 if (allocator.getBlockData(block).liveGen.get(operandNum)) { 387 usedIn.add(block); 388 try (Indent indent3 = Debug.logAndIndent("used in block B%d", block.getId())) { 389 for (LIRInstruction ins : allocator.getLIR().getLIRforBlock(block)) { 390 try (Indent indent4 = Debug.logAndIndent("%d: %s", ins.id(), ins)) { 391 ins.forEachState((liveStateOperand, mode, flags) -> { 392 Debug.log("operand=%s", liveStateOperand); 393 return liveStateOperand; 394 }); 395 } 396 } 397 } 398 } 399 if (allocator.getBlockData(block).liveKill.get(operandNum)) { 400 definedIn.add(block); 401 try (Indent indent3 = Debug.logAndIndent("defined in block B%d", block.getId())) { 402 for (LIRInstruction ins : allocator.getLIR().getLIRforBlock(block)) { 403 Debug.log("%d: %s", ins.id(), ins); 404 } 405 } 406 } 407 } 408 409 int[] hitCount = new int[numBlocks]; 410 411 while (!definedIn.isEmpty()) { 412 AbstractBlockBase<?> block = definedIn.removeFirst(); 413 usedIn.remove(block); 414 for (AbstractBlockBase<?> successor : block.getSuccessors()) { 415 if (successor.isLoopHeader()) { 416 if (!block.isLoopEnd()) { 417 definedIn.add(successor); 418 } 419 } else { 420 if (++hitCount[successor.getId()] == successor.getPredecessorCount()) { 421 definedIn.add(successor); 422 } 423 } 424 } 425 } 426 try (Indent indent3 = Debug.logAndIndent("**** offending usages are in: ")) { 427 for (AbstractBlockBase<?> block : usedIn) { 428 Debug.log("B%d", block.getId()); 429 } 430 } 431 } 432 } 433 } 434 } catch (Throwable e) { 435 throw Debug.handle(e); 436 } 437 } 438 439 protected void verifyLiveness() { 440 /* 441 * Check that fixed intervals are not live at block boundaries (live set must be empty at 442 * fixed intervals). 443 */ 444 for (AbstractBlockBase<?> block : allocator.sortedBlocks()) { 445 for (int j = 0; j <= allocator.maxRegisterNumber(); j++) { 446 assert !allocator.getBlockData(block).liveIn.get(j) : "liveIn set of fixed register must be empty"; 447 assert !allocator.getBlockData(block).liveOut.get(j) : "liveOut set of fixed register must be empty"; 448 assert !allocator.getBlockData(block).liveGen.get(j) : "liveGen set of fixed register must be empty"; 449 } 450 } 451 } 452 453 protected void addUse(AllocatableValue operand, int from, int to, RegisterPriority registerPriority, LIRKind kind) { 454 if (!allocator.isProcessed(operand)) { 455 return; 456 } 457 458 Interval interval = allocator.getOrCreateInterval(operand); 459 if (!kind.equals(LIRKind.Illegal)) { 460 interval.setKind(kind); 461 } 462 463 interval.addRange(from, to); 464 465 // Register use position at even instruction id. 466 interval.addUsePos(to & ~1, registerPriority); 467 468 if (Debug.isLogEnabled()) { 469 Debug.log("add use: %s, from %d to %d (%s)", interval, from, to, registerPriority.name()); 470 } 471 } 472 473 protected void addTemp(AllocatableValue operand, int tempPos, RegisterPriority registerPriority, LIRKind kind) { 474 if (!allocator.isProcessed(operand)) { 475 return; 476 } 477 478 Interval interval = allocator.getOrCreateInterval(operand); 479 if (!kind.equals(LIRKind.Illegal)) { 480 interval.setKind(kind); 481 } 482 483 interval.addRange(tempPos, tempPos + 1); 484 interval.addUsePos(tempPos, registerPriority); 485 interval.addMaterializationValue(null); 486 487 if (Debug.isLogEnabled()) { 488 Debug.log("add temp: %s tempPos %d (%s)", interval, tempPos, RegisterPriority.MustHaveRegister.name()); 489 } 490 } 491 492 protected void addDef(AllocatableValue operand, LIRInstruction op, RegisterPriority registerPriority, LIRKind kind) { 493 if (!allocator.isProcessed(operand)) { 494 return; 495 } 496 int defPos = op.id(); 497 498 Interval interval = allocator.getOrCreateInterval(operand); 499 if (!kind.equals(LIRKind.Illegal)) { 500 interval.setKind(kind); 501 } 502 503 Range r = interval.first(); 504 if (r.from <= defPos) { 505 /* 506 * Update the starting point (when a range is first created for a use, its start is the 507 * beginning of the current block until a def is encountered). 508 */ 509 r.from = defPos; 510 interval.addUsePos(defPos, registerPriority); 511 512 } else { 513 /* 514 * Dead value - make vacuous interval also add register priority for dead intervals 515 */ 516 interval.addRange(defPos, defPos + 1); 517 interval.addUsePos(defPos, registerPriority); 518 if (Debug.isLogEnabled()) { 519 Debug.log("Warning: def of operand %s at %d occurs without use", operand, defPos); 520 } 521 } 522 523 changeSpillDefinitionPos(op, operand, interval, defPos); 524 if (registerPriority == RegisterPriority.None && interval.spillState().ordinal() <= SpillState.StartInMemory.ordinal() && isStackSlot(operand)) { 525 // detection of method-parameters and roundfp-results 526 interval.setSpillState(SpillState.StartInMemory); 527 } 528 interval.addMaterializationValue(getMaterializedValue(op, operand, interval)); 529 530 if (Debug.isLogEnabled()) { 531 Debug.log("add def: %s defPos %d (%s)", interval, defPos, registerPriority.name()); 532 } 533 } 534 535 /** 536 * Optimizes moves related to incoming stack based arguments. The interval for the destination 537 * of such moves is assigned the stack slot (which is in the caller's frame) as its spill slot. 538 */ 539 protected void handleMethodArguments(LIRInstruction op) { 540 if (op instanceof MoveOp) { 541 MoveOp move = (MoveOp) op; 542 if (optimizeMethodArgument(move.getInput())) { 543 StackSlot slot = asStackSlot(move.getInput()); 544 if (DetailedAsserts.getValue()) { 545 assert op.id() > 0 : "invalid id"; 546 assert allocator.blockForId(op.id()).getPredecessorCount() == 0 : "move from stack must be in first block"; 547 assert isVariable(move.getResult()) : "result of move must be a variable"; 548 549 if (Debug.isLogEnabled()) { 550 Debug.log("found move from stack slot %s to %s", slot, move.getResult()); 551 } 552 } 553 554 Interval interval = allocator.intervalFor(move.getResult()); 555 interval.setSpillSlot(slot); 556 interval.assignLocation(slot); 557 } 558 } else if (op instanceof StackStoreOp) { 559 StackStoreOp store = (StackStoreOp) op; 560 StackSlot slot = asStackSlot(store.getStackSlot()); 561 Interval interval = allocator.intervalFor(store.getResult()); 562 interval.setSpillSlot(slot); 563 interval.setSpillState(SpillState.StartInMemory); 564 } 565 } 566 567 protected void addRegisterHint(final LIRInstruction op, final Value targetValue, OperandMode mode, EnumSet<OperandFlag> flags, final boolean hintAtDef) { 568 if (flags.contains(OperandFlag.HINT) && LinearScan.isVariableOrRegister(targetValue)) { 569 570 op.forEachRegisterHint(targetValue, mode, (registerHint, valueMode, valueFlags) -> { 571 if (LinearScan.isVariableOrRegister(registerHint)) { 572 Interval from = allocator.getOrCreateInterval((AllocatableValue) registerHint); 573 Interval to = allocator.getOrCreateInterval((AllocatableValue) targetValue); 574 575 /* hints always point from def to use */ 576 if (hintAtDef) { 577 to.setLocationHint(from); 578 } else { 579 from.setLocationHint(to); 580 } 581 if (Debug.isLogEnabled()) { 582 Debug.log("operation at opId %d: added hint from interval %d to %d", op.id(), from.operandNumber, to.operandNumber); 583 } 584 585 return registerHint; 586 } 587 return null; 588 }); 589 } 590 } 591 592 /** 593 * Eliminates moves from register to stack if the stack slot is known to be correct. 594 * 595 * @param op 596 * @param operand 597 */ 598 protected void changeSpillDefinitionPos(LIRInstruction op, AllocatableValue operand, Interval interval, int defPos) { 599 assert interval.isSplitParent() : "can only be called for split parents"; 600 601 switch (interval.spillState()) { 602 case NoDefinitionFound: 603 assert interval.spillDefinitionPos() == -1 : "must no be set before"; 604 interval.setSpillDefinitionPos(defPos); 605 interval.setSpillState(SpillState.NoSpillStore); 606 break; 607 608 case NoSpillStore: 609 assert defPos <= interval.spillDefinitionPos() : "positions are processed in reverse order when intervals are created"; 610 if (defPos < interval.spillDefinitionPos() - 2) { 611 // second definition found, so no spill optimization possible for this interval 612 interval.setSpillState(SpillState.NoOptimization); 613 } else { 614 // two consecutive definitions (because of two-operand LIR form) 615 assert allocator.blockForId(defPos) == allocator.blockForId(interval.spillDefinitionPos()) : "block must be equal"; 616 } 617 break; 618 619 case NoOptimization: 620 // nothing to do 621 break; 622 623 default: 624 throw new BailoutException("other states not allowed at this time"); 625 } 626 } 627 628 private static boolean optimizeMethodArgument(Value value) { 629 /* 630 * Object method arguments that are passed on the stack are currently not optimized because 631 * this requires that the runtime visits method arguments during stack walking. 632 */ 633 return isStackSlot(value) && asStackSlot(value).isInCallerFrame() && value.getKind() != Kind.Object; 634 } 635 636 /** 637 * Determines the register priority for an instruction's output/result operand. 638 */ 639 protected RegisterPriority registerPriorityOfOutputOperand(LIRInstruction op) { 640 if (op instanceof MoveOp) { 641 MoveOp move = (MoveOp) op; 642 if (optimizeMethodArgument(move.getInput())) { 643 return RegisterPriority.None; 644 } 645 } else if (op instanceof StackStoreOp) { 646 return RegisterPriority.ShouldHaveRegister; 647 } 648 649 // all other operands require a register 650 return RegisterPriority.MustHaveRegister; 651 } 652 653 /** 654 * Determines the priority which with an instruction's input operand will be allocated a 655 * register. 656 */ 657 protected static RegisterPriority registerPriorityOfInputOperand(EnumSet<OperandFlag> flags) { 658 if (flags.contains(OperandFlag.STACK)) { 659 return RegisterPriority.ShouldHaveRegister; 660 } 661 // all other operands require a register 662 return RegisterPriority.MustHaveRegister; 663 } 664 665 protected void buildIntervals() { 666 667 try (Indent indent = Debug.logAndIndent("build intervals")) { 668 InstructionValueConsumer outputConsumer = (op, operand, mode, flags) -> { 669 if (LinearScan.isVariableOrRegister(operand)) { 670 addDef((AllocatableValue) operand, op, registerPriorityOfOutputOperand(op), operand.getLIRKind()); 671 addRegisterHint(op, operand, mode, flags, true); 672 } 673 }; 674 675 InstructionValueConsumer tempConsumer = (op, operand, mode, flags) -> { 676 if (LinearScan.isVariableOrRegister(operand)) { 677 addTemp((AllocatableValue) operand, op.id(), RegisterPriority.MustHaveRegister, operand.getLIRKind()); 678 addRegisterHint(op, operand, mode, flags, false); 679 } 680 }; 681 682 InstructionValueConsumer aliveConsumer = (op, operand, mode, flags) -> { 683 if (LinearScan.isVariableOrRegister(operand)) { 684 RegisterPriority p = registerPriorityOfInputOperand(flags); 685 int opId = op.id(); 686 int blockFrom = allocator.getFirstLirInstructionId((allocator.blockForId(opId))); 687 addUse((AllocatableValue) operand, blockFrom, opId + 1, p, operand.getLIRKind()); 688 addRegisterHint(op, operand, mode, flags, false); 689 } 690 }; 691 692 InstructionValueConsumer inputConsumer = (op, operand, mode, flags) -> { 693 if (LinearScan.isVariableOrRegister(operand)) { 694 int opId = op.id(); 695 int blockFrom = allocator.getFirstLirInstructionId((allocator.blockForId(opId))); 696 RegisterPriority p = registerPriorityOfInputOperand(flags); 697 addUse((AllocatableValue) operand, blockFrom, opId, p, operand.getLIRKind()); 698 addRegisterHint(op, operand, mode, flags, false); 699 } 700 }; 701 702 InstructionValueConsumer stateProc = (op, operand, mode, flags) -> { 703 if (LinearScan.isVariableOrRegister(operand)) { 704 int opId = op.id(); 705 int blockFrom = allocator.getFirstLirInstructionId((allocator.blockForId(opId))); 706 addUse((AllocatableValue) operand, blockFrom, opId + 1, RegisterPriority.None, operand.getLIRKind()); 707 } 708 }; 709 710 // create a list with all caller-save registers (cpu, fpu, xmm) 711 Register[] callerSaveRegs = allocator.getRegisterAllocationConfig().getRegisterConfig().getCallerSaveRegisters(); 712 713 // iterate all blocks in reverse order 714 for (int i = allocator.blockCount() - 1; i >= 0; i--) { 715 716 AbstractBlockBase<?> block = allocator.blockAt(i); 717 try (Indent indent2 = Debug.logAndIndent("handle block %d", block.getId())) { 718 719 List<LIRInstruction> instructions = allocator.getLIR().getLIRforBlock(block); 720 final int blockFrom = allocator.getFirstLirInstructionId(block); 721 int blockTo = allocator.getLastLirInstructionId(block); 722 723 assert blockFrom == instructions.get(0).id(); 724 assert blockTo == instructions.get(instructions.size() - 1).id(); 725 726 // Update intervals for operands live at the end of this block; 727 BitSet live = allocator.getBlockData(block).liveOut; 728 for (int operandNum = live.nextSetBit(0); operandNum >= 0; operandNum = live.nextSetBit(operandNum + 1)) { 729 assert live.get(operandNum) : "should not stop here otherwise"; 730 AllocatableValue operand = allocator.intervalFor(operandNum).operand; 731 if (Debug.isLogEnabled()) { 732 Debug.log("live in %d: %s", operandNum, operand); 733 } 734 735 addUse(operand, blockFrom, blockTo + 2, RegisterPriority.None, LIRKind.Illegal); 736 737 /* 738 * Add special use positions for loop-end blocks when the interval is used 739 * anywhere inside this loop. It's possible that the block was part of a 740 * non-natural loop, so it might have an invalid loop index. 741 */ 742 if (block.isLoopEnd() && block.getLoop() != null && isIntervalInLoop(operandNum, block.getLoop().getIndex())) { 743 allocator.intervalFor(operandNum).addUsePos(blockTo + 1, RegisterPriority.LiveAtLoopEnd); 744 } 745 } 746 747 /* 748 * Iterate all instructions of the block in reverse order. definitions of 749 * intervals are processed before uses. 750 */ 751 for (int j = instructions.size() - 1; j >= 0; j--) { 752 final LIRInstruction op = instructions.get(j); 753 final int opId = op.id(); 754 755 try (Indent indent3 = Debug.logAndIndent("handle inst %d: %s", opId, op)) { 756 757 // add a temp range for each register if operation destroys 758 // caller-save registers 759 if (op.destroysCallerSavedRegisters()) { 760 for (Register r : callerSaveRegs) { 761 if (allocator.attributes(r).isAllocatable()) { 762 addTemp(r.asValue(), opId, RegisterPriority.None, LIRKind.Illegal); 763 } 764 } 765 if (Debug.isLogEnabled()) { 766 Debug.log("operation destroys all caller-save registers"); 767 } 768 } 769 770 op.visitEachOutput(outputConsumer); 771 op.visitEachTemp(tempConsumer); 772 op.visitEachAlive(aliveConsumer); 773 op.visitEachInput(inputConsumer); 774 775 /* 776 * Add uses of live locals from interpreter's point of view for proper 777 * debug information generation. Treat these operands as temp values (if 778 * the live range is extended to a call site, the value would be in a 779 * register at the call otherwise). 780 */ 781 op.visitEachState(stateProc); 782 783 // special steps for some instructions (especially moves) 784 handleMethodArguments(op); 785 786 } 787 788 } // end of instruction iteration 789 } 790 } // end of block iteration 791 792 /* 793 * Add the range [0, 1] to all fixed intervals. the register allocator need not handle 794 * unhandled fixed intervals. 795 */ 796 for (Interval interval : allocator.intervals()) { 797 if (interval != null && isRegister(interval.operand)) { 798 interval.addRange(0, 1); 799 } 800 } 801 } 802 } 803 804 /** 805 * Returns a value for a interval definition, which can be used for re-materialization. 806 * 807 * @param op An instruction which defines a value 808 * @param operand The destination operand of the instruction 809 * @param interval The interval for this defined value. 810 * @return Returns the value which is moved to the instruction and which can be reused at all 811 * reload-locations in case the interval of this instruction is spilled. Currently this 812 * can only be a {@link JavaConstant}. 813 */ 814 protected static JavaConstant getMaterializedValue(LIRInstruction op, Value operand, Interval interval) { 815 if (op instanceof MoveOp) { 816 MoveOp move = (MoveOp) op; 817 if (move.getInput() instanceof JavaConstant) { 818 /* 819 * Check if the interval has any uses which would accept an stack location (priority 820 * == ShouldHaveRegister). Rematerialization of such intervals can result in a 821 * degradation, because rematerialization always inserts a constant load, even if 822 * the value is not needed in a register. 823 */ 824 Interval.UsePosList usePosList = interval.usePosList(); 825 int numUsePos = usePosList.size(); 826 for (int useIdx = 0; useIdx < numUsePos; useIdx++) { 827 Interval.RegisterPriority priority = usePosList.registerPriority(useIdx); 828 if (priority == Interval.RegisterPriority.ShouldHaveRegister) { 829 return null; 830 } 831 } 832 return (JavaConstant) move.getInput(); 833 } 834 } 835 return null; 836 } 837}