TraceLinearScanLifetimeAnalysisPhase.java revision 13264:48566d838608
1139825Simp/* 21541Srgrimes * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. 31541Srgrimes * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 41541Srgrimes * 51541Srgrimes * This code is free software; you can redistribute it and/or modify it 61541Srgrimes * under the terms of the GNU General Public License version 2 only, as 71541Srgrimes * published by the Free Software Foundation. 81541Srgrimes * 91541Srgrimes * This code is distributed in the hope that it will be useful, but WITHOUT 101541Srgrimes * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 111541Srgrimes * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 121541Srgrimes * version 2 for more details (a copy is included in the LICENSE file that 131541Srgrimes * accompanied this code). 141541Srgrimes * 151541Srgrimes * You should have received a copy of the GNU General Public License version 161541Srgrimes * 2 along with this work; if not, write to the Free Software Foundation, 171541Srgrimes * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 181541Srgrimes * 191541Srgrimes * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 201541Srgrimes * or visit www.oracle.com if you need additional information or have any 211541Srgrimes * questions. 221541Srgrimes */ 231541Srgrimespackage org.graalvm.compiler.lir.alloc.trace.lsra; 241541Srgrimes 251541Srgrimesimport static jdk.vm.ci.code.ValueUtil.asRegisterValue; 261541Srgrimesimport static jdk.vm.ci.code.ValueUtil.asStackSlot; 271541Srgrimesimport static jdk.vm.ci.code.ValueUtil.isRegister; 281541Srgrimesimport static jdk.vm.ci.code.ValueUtil.isStackSlot; 291541Srgrimesimport static org.graalvm.compiler.lir.LIRValueUtil.asVariable; 301541Srgrimesimport static org.graalvm.compiler.lir.LIRValueUtil.isStackSlotValue; 311541Srgrimesimport static org.graalvm.compiler.lir.LIRValueUtil.isVariable; 32116226Sobrienimport static org.graalvm.compiler.lir.alloc.trace.TraceRegisterAllocationPhase.Options.TraceRAshareSpillInformation; 33116226Sobrienimport static org.graalvm.compiler.lir.alloc.trace.TraceRegisterAllocationPhase.Options.TraceRAuseInterTraceHints; 34116226Sobrienimport static org.graalvm.compiler.lir.alloc.trace.TraceUtil.asShadowedRegisterValue; 351541Srgrimesimport static org.graalvm.compiler.lir.alloc.trace.TraceUtil.isShadowedRegisterValue; 361541Srgrimesimport static org.graalvm.compiler.lir.alloc.trace.lsra.TraceLinearScanPhase.isVariableOrRegister; 371541Srgrimes 3876166Smarkmimport java.util.ArrayList; 3976166Smarkmimport java.util.EnumSet; 4076166Smarkm 4134924Sbdeimport org.graalvm.compiler.core.common.LIRKind; 4274927Sjhbimport org.graalvm.compiler.core.common.alloc.RegisterAllocationConfig; 4312662Sdgimport org.graalvm.compiler.core.common.alloc.Trace; 4493823Sdillonimport org.graalvm.compiler.core.common.alloc.TraceBuilderResult; 4512662Sdgimport org.graalvm.compiler.core.common.cfg.AbstractBlockBase; 461541Srgrimesimport org.graalvm.compiler.debug.DebugContext; 4740794Speterimport org.graalvm.compiler.debug.GraalError; 4812726Sbdeimport org.graalvm.compiler.debug.Indent; 4912662Sdgimport org.graalvm.compiler.lir.InstructionValueConsumer; 5012662Sdgimport org.graalvm.compiler.lir.LIR; 5112662Sdgimport org.graalvm.compiler.lir.LIRInstruction; 5212662Sdgimport org.graalvm.compiler.lir.LIRInstruction.OperandFlag; 531541Srgrimesimport org.graalvm.compiler.lir.LIRInstruction.OperandMode; 541541Srgrimesimport org.graalvm.compiler.lir.LIRValueUtil; 55170170Sattilioimport org.graalvm.compiler.lir.StandardOp.JumpOp; 561541Srgrimesimport org.graalvm.compiler.lir.StandardOp.LabelOp; 5776778Sjhbimport org.graalvm.compiler.lir.StandardOp.LoadConstantOp; 581541Srgrimesimport org.graalvm.compiler.lir.StandardOp.ValueMoveOp; 5962622Sjhbimport org.graalvm.compiler.lir.ValueProcedure; 60170170Sattilioimport org.graalvm.compiler.lir.Variable; 6162622Sjhbimport org.graalvm.compiler.lir.alloc.trace.GlobalLivenessInfo; 62170170Sattilioimport org.graalvm.compiler.lir.alloc.trace.ShadowedRegisterValue; 6362622Sjhbimport org.graalvm.compiler.lir.alloc.trace.lsra.TraceInterval.RegisterPriority; 64170170Sattilioimport org.graalvm.compiler.lir.alloc.trace.lsra.TraceInterval.SpillState; 6562622Sjhbimport org.graalvm.compiler.lir.alloc.trace.lsra.TraceLinearScanPhase.TraceLinearScan; 66170170Sattilioimport org.graalvm.compiler.lir.gen.LIRGenerationResult; 6762622Sjhbimport org.graalvm.compiler.lir.gen.LIRGeneratorTool.MoveFactory; 68170170Sattilioimport org.graalvm.compiler.lir.ssa.SSAUtil; 6962622Sjhb 70170170Sattilioimport jdk.vm.ci.code.Register; 7162622Sjhbimport jdk.vm.ci.code.RegisterArray; 72170170Sattilioimport jdk.vm.ci.code.RegisterValue; 7362622Sjhbimport jdk.vm.ci.code.TargetDescription; 74170170Sattilioimport jdk.vm.ci.meta.AllocatableValue; 7512286Sphkimport jdk.vm.ci.meta.JavaConstant; 76136404Speterimport jdk.vm.ci.meta.Value; 77136404Speter 78136404Speterpublic final class TraceLinearScanLifetimeAnalysisPhase extends TraceLinearScanAllocationPhase { 79136404Speter 80136404Speter @Override 811541Srgrimes protected void run(TargetDescription target, LIRGenerationResult lirGenRes, Trace trace, MoveFactory spillMoveFactory, RegisterAllocationConfig registerAllocationConfig, 82136404Speter TraceBuilderResult traceBuilderResult, TraceLinearScan allocator) { 83136404Speter new Analyser(allocator, traceBuilderResult).analyze(); 84136404Speter } 85136404Speter 86136404Speter public static final class Analyser { 87136404Speter private final TraceLinearScan allocator; 88136404Speter private final DebugContext debug; 89136404Speter private final TraceBuilderResult traceBuilderResult; 90136404Speter private int numInstructions; 91136404Speter 92136404Speter public Analyser(TraceLinearScan allocator, TraceBuilderResult traceBuilderResult) { 93136404Speter this.allocator = allocator; 94136404Speter this.debug = allocator.getDebug(); 9512286Sphk this.traceBuilderResult = traceBuilderResult; 9662573Sphk } 971541Srgrimes 9899072Sjulian private AbstractBlockBase<?>[] sortedBlocks() { 9912286Sphk return allocator.sortedBlocks(); 100164437Sru } 10112286Sphk 10212286Sphk private LIR getLIR() { 10312286Sphk return allocator.getLIR(); 1041541Srgrimes } 10599072Sjulian 106159054Stegge private RegisterArray getCallerSavedRegisters() { 1071541Srgrimes return allocator.getRegisterAllocationConfig().getRegisterConfig().getCallerSaveRegisters(); 108164437Sru } 1091541Srgrimes 1101541Srgrimes public void analyze() { 1111541Srgrimes countInstructions(); 11279224Sdillon buildIntervals(); 11395112Salc } 114108551Salc 115124083Salc private boolean isAllocated(AbstractBlockBase<?> currentBlock, AbstractBlockBase<?> other) { 116124083Salc return traceBuilderResult.getTraceForBlock(other).getId() < traceBuilderResult.getTraceForBlock(currentBlock).getId(); 117124083Salc } 118124083Salc 119124083Salc /** 120124083Salc * Count instructions in all blocks. The numbering follows the 121124083Salc * {@linkplain TraceLinearScan#sortedBlocks() register allocation order}. 122124083Salc */ 12338517Sdfr private void countInstructions() { 124113448Salc 125108551Salc allocator.initIntervals(); 12695112Salc 1271541Srgrimes int numberInstructions = 0; 1281541Srgrimes for (AbstractBlockBase<?> block : sortedBlocks()) { 1291541Srgrimes numberInstructions += getLIR().getLIRforBlock(block).size(); 13074927Sjhb } 13183366Sjulian numInstructions = numberInstructions; 1321541Srgrimes 1331541Srgrimes // initialize with correct length 134170307Sjeff allocator.initOpIdMaps(numberInstructions); 13599072Sjulian } 13699072Sjulian 137170307Sjeff private final InstructionValueConsumer outputConsumer = new InstructionValueConsumer() { 1381541Srgrimes @Override 1391541Srgrimes public void visitValue(LIRInstruction op, Value operand, OperandMode mode, EnumSet<OperandFlag> flags) { 14099072Sjulian if (isVariableOrRegister(operand)) { 14199072Sjulian addDef((AllocatableValue) operand, op, registerPriorityOfOutputOperand(op)); 142103216Sjulian addRegisterHint(op, operand, mode, flags, true); 143170307Sjeff } 14499072Sjulian } 145103216Sjulian }; 146170307Sjeff 147170307Sjeff private final InstructionValueConsumer tempConsumer = new InstructionValueConsumer() { 148170307Sjeff @Override 149104387Sjhb public void visitValue(LIRInstruction op, Value operand, OperandMode mode, EnumSet<OperandFlag> flags) { 150103216Sjulian if (isVariableOrRegister(operand)) { 151103216Sjulian addTemp((AllocatableValue) operand, op.id(), RegisterPriority.MustHaveRegister); 152164437Sru addRegisterHint(op, operand, mode, flags, false); 153103216Sjulian } 154103216Sjulian } 155103216Sjulian }; 15699072Sjulian private final InstructionValueConsumer aliveConsumer = new InstructionValueConsumer() { 157164437Sru @Override 158103216Sjulian public void visitValue(LIRInstruction op, Value operand, OperandMode mode, EnumSet<OperandFlag> flags) { 159164437Sru if (isVariableOrRegister(operand)) { 16099072Sjulian RegisterPriority p = registerPriorityOfInputOperand(flags); 16199072Sjulian int opId = op.id(); 1621541Srgrimes int blockFrom = 0; 163103216Sjulian addUse((AllocatableValue) operand, blockFrom, opId + 1, p); 164164437Sru addRegisterHint(op, operand, mode, flags, false); 165103216Sjulian } 16699072Sjulian } 16799072Sjulian }; 168164437Sru 169170307Sjeff private final InstructionValueConsumer inputConsumer = new InstructionValueConsumer() { 17099072Sjulian @Override 17199072Sjulian public void visitValue(LIRInstruction op, Value operand, OperandMode mode, EnumSet<OperandFlag> flags) { 17299072Sjulian if (isVariableOrRegister(operand)) { 17399072Sjulian int opId = op.id(); 174170307Sjeff RegisterPriority p = registerPriorityOfInputOperand(flags); 17571572Sjhb int blockFrom = 0; 1761541Srgrimes addUse((AllocatableValue) operand, blockFrom, opId, p); 177170307Sjeff addRegisterHint(op, operand, mode, flags, false); 1781541Srgrimes } 1791541Srgrimes } 1801541Srgrimes 1811541Srgrimes }; 182159054Stegge 183159054Stegge private final InstructionValueConsumer stateProc = new InstructionValueConsumer() { 184159054Stegge @Override 185159054Stegge public void visitValue(LIRInstruction op, Value operand, OperandMode mode, EnumSet<OperandFlag> flags) { 186108585Salc if (isVariableOrRegister(operand)) { 187108585Salc int opId = op.id(); 1885455Sdg int blockFrom = 0; 18943748Sdillon addUse((AllocatableValue) operand, blockFrom, opId + 1, RegisterPriority.None); 190108585Salc } 1911541Srgrimes } 192113448Salc }; 193108585Salc 194108585Salc private void addUse(AllocatableValue operand, int from, int to, RegisterPriority registerPriority) { 195113448Salc if (isRegister(operand)) { 1961541Srgrimes RegisterValue reg = asRegisterValue(operand); 197108585Salc if (allocator.isAllocatable(reg)) { 198159054Stegge addFixedUse(reg, from, to); 1991541Srgrimes } 200164437Sru } else { 2011541Srgrimes assert isVariable(operand) : operand; 20274927Sjhb addVariableUse(asVariable(operand), from, to, registerPriority); 2031541Srgrimes } 2041541Srgrimes } 2051541Srgrimes 20695112Salc private void addFixedUse(RegisterValue reg, int from, int to) { 20775523Salfred FixedInterval interval = allocator.getOrCreateFixedInterval(reg); 20842957Sdillon interval.addRange(from, to); 209124083Salc if (debug.isLogEnabled()) { 210124083Salc debug.log("add fixed use: %s, at %d", interval, to); 211124083Salc } 212124083Salc } 21342957Sdillon 214108585Salc private void addVariableUse(Variable operand, int from, int to, RegisterPriority registerPriority) { 215124083Salc TraceInterval interval = allocator.getOrCreateInterval(operand); 216124083Salc interval.addRange(from, to); 217124083Salc 21842957Sdillon // Register use position at even instruction id. 219108585Salc interval.addUsePos(to & ~1, registerPriority, allocator.getOptions()); 220164429Sru 221164429Sru if (debug.isLogEnabled()) { 222164429Sru debug.log("add use: %s, at %d (%s)", interval, to, registerPriority.name()); 223164429Sru } 224164429Sru } 225164429Sru 226164429Sru private void addDef(AllocatableValue operand, LIRInstruction op, RegisterPriority registerPriority) { 227164437Sru if (isRegister(operand)) { 228164437Sru RegisterValue reg = asRegisterValue(operand); 2291541Srgrimes if (allocator.isAllocatable(reg)) { 230164437Sru addFixedDef(reg, op); 231164437Sru } 2321541Srgrimes } else { 23318169Sdyson assert isVariable(operand) : operand; 2341541Srgrimes addVariableDef(asVariable(operand), op, registerPriority); 235164437Sru } 236164437Sru } 2371541Srgrimes 238164437Sru private void addFixedDef(RegisterValue reg, LIRInstruction op) { 239164437Sru FixedInterval interval = allocator.getOrCreateFixedInterval(reg); 2401541Srgrimes int defPos = op.id(); 2411541Srgrimes if (interval.from() <= defPos) { 2421541Srgrimes /* 24395112Salc * Update the starting point (when a range is first created for a use, its start is 244170170Sattilio * the beginning of the current block until a def is encountered). 245164437Sru */ 2461541Srgrimes interval.setFrom(defPos); 24712286Sphk 24893823Sdillon } else { 24993823Sdillon /* 25093823Sdillon * Dead value - make vacuous interval also add register priority for dead intervals 25193823Sdillon */ 25293823Sdillon interval.addRange(defPos, defPos + 1); 25393823Sdillon if (debug.isLogEnabled()) { 25493823Sdillon debug.log("Warning: def of operand %s at %d occurs without use", reg, defPos); 25593823Sdillon } 25693823Sdillon } 25793823Sdillon if (debug.isLogEnabled()) { 25893823Sdillon debug.log("add fixed def: %s, at %d", interval, defPos); 25993823Sdillon } 26093823Sdillon } 26193823Sdillon 26293823Sdillon private TraceInterval addVariableDef(Variable operand, LIRInstruction op, RegisterPriority registerPriority) { 26393823Sdillon int defPos = op.id(); 264170170Sattilio 26593823Sdillon TraceInterval interval = allocator.getOrCreateInterval(operand); 26693823Sdillon 26793823Sdillon if (interval.isEmpty()) { 26893823Sdillon /* 26993823Sdillon * Dead value - make vacuous interval also add register priority for dead intervals 27093823Sdillon */ 27193823Sdillon interval.addRange(defPos, defPos + 1); 272108171Sdillon if (debug.isLogEnabled()) { 273108171Sdillon debug.log("Warning: def of operand %s at %d occurs without use", operand, defPos); 27493823Sdillon } 275144970Sjhb } else { 27693823Sdillon /* 27793823Sdillon * Update the starting point (when a range is first created for a use, its start is 278109097Sdillon * the beginning of the current block until a def is encountered). 27946381Sbillf */ 28046381Sbillf interval.setFrom(defPos); 281141696Sphk } 282141630Sphk if (!(op instanceof LabelOp)) { 283141630Sphk // no use positions for labels 284141630Sphk interval.addUsePos(defPos, registerPriority, allocator.getOptions()); 285141630Sphk } 28640794Speter 28793823Sdillon changeSpillDefinitionPos(op, operand, interval, defPos); 28893823Sdillon if (registerPriority == RegisterPriority.None && interval.spillState().ordinal() <= SpillState.StartInMemory.ordinal() && isStackSlot(operand)) { 289170170Sattilio // detection of method-parameters and roundfp-results 29093823Sdillon interval.setSpillState(SpillState.StartInMemory); 291170170Sattilio } 29293823Sdillon interval.addMaterializationValue(getMaterializedValue(op, operand, interval, allocator.neverSpillConstants(), allocator.getSpillMoveFactory())); 293170170Sattilio 29493823Sdillon if (debug.isLogEnabled()) { 295170170Sattilio debug.log("add def: %s defPos %d (%s)", interval, defPos, registerPriority.name()); 29693823Sdillon } 297170170Sattilio return interval; 29893823Sdillon } 299170170Sattilio 30093823Sdillon private void addTemp(AllocatableValue operand, int tempPos, RegisterPriority registerPriority) { 301170170Sattilio if (isRegister(operand)) { 30293823Sdillon RegisterValue reg = asRegisterValue(operand); 303170170Sattilio if (allocator.isAllocatable(reg)) { 30493823Sdillon addFixedTemp(reg, tempPos); 305170170Sattilio } 30693823Sdillon } else { 307170170Sattilio assert isVariable(operand) : operand; 30893823Sdillon addVariableTemp(asVariable(operand), tempPos, registerPriority); 309170170Sattilio } 31093823Sdillon } 311170170Sattilio 31293823Sdillon private void addFixedTemp(RegisterValue reg, int tempPos) { 313170170Sattilio FixedInterval interval = allocator.getOrCreateFixedInterval(reg); 31493823Sdillon interval.addRange(tempPos, tempPos + 1); 315170170Sattilio if (debug.isLogEnabled()) { 31693823Sdillon debug.log("add fixed temp: %s, at %d", interval, tempPos); 317170170Sattilio } 31893823Sdillon } 319170170Sattilio 32093823Sdillon private void addVariableTemp(Variable operand, int tempPos, RegisterPriority registerPriority) { 321170170Sattilio TraceInterval interval = allocator.getOrCreateInterval(operand); 32293823Sdillon 323170170Sattilio if (interval.isEmpty()) { 32493823Sdillon interval.addRange(tempPos, tempPos + 1); 325170170Sattilio } else if (interval.from() > tempPos) { 32693823Sdillon interval.setFrom(tempPos); 327170170Sattilio } 32893823Sdillon 329170170Sattilio interval.addUsePos(tempPos, registerPriority, allocator.getOptions()); 33093823Sdillon interval.addMaterializationValue(null); 331170170Sattilio 332171633Salc if (debug.isLogEnabled()) { 333171633Salc debug.log("add temp: %s tempPos %d (%s)", interval, tempPos, RegisterPriority.MustHaveRegister.name()); 33493823Sdillon } 335170170Sattilio } 33693823Sdillon 337170170Sattilio /** 33893823Sdillon * Eliminates moves from register to stack if the stack slot is known to be correct. 339170170Sattilio * 34093823Sdillon * @param op 341170170Sattilio * @param operand 34293823Sdillon */ 343170170Sattilio private void changeSpillDefinitionPos(LIRInstruction op, AllocatableValue operand, TraceInterval interval, int defPos) { 34493823Sdillon assert interval.isSplitParent() : "can only be called for split parents"; 345170170Sattilio 34693823Sdillon switch (interval.spillState()) { 347170170Sattilio case NoDefinitionFound: 34893823Sdillon // assert interval.spillDefinitionPos() == -1 : "must no be set before"; 349170170Sattilio interval.setSpillDefinitionPos(defPos); 35093823Sdillon if (!(op instanceof LabelOp)) { 351170170Sattilio // Do not update state for labels. This will be done afterwards. 35293823Sdillon interval.setSpillState(SpillState.NoSpillStore); 353170170Sattilio } 35493823Sdillon break; 355170170Sattilio 35693823Sdillon case NoSpillStore: 357170170Sattilio assert defPos <= interval.spillDefinitionPos() : "positions are processed in reverse order when intervals are created"; 35893823Sdillon if (defPos < interval.spillDefinitionPos() - 2) { 359170170Sattilio /* 36093823Sdillon * Second definition found, so no spill optimization possible for this 361170170Sattilio * interval. 36293823Sdillon */ 363170170Sattilio interval.setSpillState(SpillState.NoOptimization); 36493823Sdillon } else { 365170170Sattilio // two consecutive definitions (because of two-operand LIR form) 36693823Sdillon assert allocator.blockForId(defPos) == allocator.blockForId(interval.spillDefinitionPos()) : "block must be equal"; 367170170Sattilio } 368170170Sattilio break; 369170170Sattilio 37093823Sdillon case NoOptimization: 371170170Sattilio // nothing to do 37293823Sdillon break; 373170170Sattilio 37493823Sdillon default: 375170170Sattilio throw GraalError.shouldNotReachHere("other states not allowed at this time"); 37693823Sdillon } 377170170Sattilio } 37893823Sdillon 379170170Sattilio private void addRegisterHint(final LIRInstruction op, final Value targetValue, OperandMode mode, EnumSet<OperandFlag> flags, final boolean hintAtDef) { 38093823Sdillon if (flags.contains(OperandFlag.HINT) && isVariableOrRegister(targetValue)) { 381170170Sattilio 38293823Sdillon ValueProcedure registerHintProc = new ValueProcedure() { 383170170Sattilio @Override 38493823Sdillon public Value doValue(Value registerHint, OperandMode valueMode, EnumSet<OperandFlag> valueFlags) { 385170170Sattilio if (isVariableOrRegister(registerHint)) { 38693823Sdillon /* 38740794Speter * TODO (je): clean up 38840794Speter */ 389 final AllocatableValue fromValue; 390 final AllocatableValue toValue; 391 /* hints always point from def to use */ 392 if (hintAtDef) { 393 fromValue = (AllocatableValue) registerHint; 394 toValue = (AllocatableValue) targetValue; 395 } else { 396 fromValue = (AllocatableValue) targetValue; 397 toValue = (AllocatableValue) registerHint; 398 } 399 debug.log("addRegisterHint %s to %s", fromValue, toValue); 400 final TraceInterval to; 401 final IntervalHint from; 402 if (isRegister(toValue)) { 403 if (isRegister(fromValue)) { 404 // fixed to fixed move 405 return null; 406 } 407 from = getIntervalHint(toValue); 408 to = allocator.getOrCreateInterval(asVariable(fromValue)); 409 } else { 410 to = allocator.getOrCreateInterval(asVariable(toValue)); 411 from = getIntervalHint(fromValue); 412 } 413 414 to.setLocationHint(from); 415 if (debug.isLogEnabled()) { 416 debug.log("operation at opId %d: added hint from interval %s to %s", op.id(), from, to); 417 } 418 419 return registerHint; 420 } 421 return null; 422 } 423 }; 424 op.forEachRegisterHint(targetValue, mode, registerHintProc); 425 } 426 } 427 428 private static boolean optimizeMethodArgument(Value value) { 429 /* 430 * Object method arguments that are passed on the stack are currently not optimized 431 * because this requires that the runtime visits method arguments during stack walking. 432 */ 433 return isStackSlot(value) && asStackSlot(value).isInCallerFrame() && LIRKind.isValue(value); 434 } 435 436 /** 437 * Determines the register priority for an instruction's output/result operand. 438 */ 439 private static RegisterPriority registerPriorityOfOutputOperand(LIRInstruction op) { 440 if (op instanceof LabelOp) { 441 // skip method header 442 return RegisterPriority.None; 443 } 444 if (ValueMoveOp.isValueMoveOp(op)) { 445 ValueMoveOp move = ValueMoveOp.asValueMoveOp(op); 446 if (optimizeMethodArgument(move.getInput())) { 447 return RegisterPriority.None; 448 } 449 } 450 451 // all other operands require a register 452 return RegisterPriority.MustHaveRegister; 453 } 454 455 /** 456 * Determines the priority which with an instruction's input operand will be allocated a 457 * register. 458 */ 459 private static RegisterPriority registerPriorityOfInputOperand(EnumSet<OperandFlag> flags) { 460 if (flags.contains(OperandFlag.OUTGOING)) { 461 return RegisterPriority.None; 462 } 463 if (flags.contains(OperandFlag.STACK)) { 464 return RegisterPriority.ShouldHaveRegister; 465 } 466 // all other operands require a register 467 return RegisterPriority.MustHaveRegister; 468 } 469 470 @SuppressWarnings("try") 471 private void buildIntervals() { 472 473 try (Indent indent = debug.logAndIndent("build intervals")) { 474 475 // create a list with all caller-save registers (cpu, fpu, xmm) 476 RegisterArray callerSaveRegs = getCallerSavedRegisters(); 477 int instructionIndex = numInstructions; 478 479 // iterate all blocks in reverse order 480 AbstractBlockBase<?>[] blocks = sortedBlocks(); 481 for (int blockId = blocks.length - 1; blockId >= 0; blockId--) { 482 final AbstractBlockBase<?> block = blocks[blockId]; 483 484 try (Indent indent2 = debug.logAndIndent("handle block %d", block.getId())) { 485 handleBlockEnd(block, (instructionIndex - 1) << 1); 486 487 /* 488 * Iterate all instructions of the block in reverse order. definitions of 489 * intervals are processed before uses. 490 */ 491 ArrayList<LIRInstruction> instructions = getLIR().getLIRforBlock(block); 492 for (int instIdx = instructions.size() - 1; instIdx >= 1; instIdx--) { 493 final LIRInstruction op = instructions.get(instIdx); 494 // number instruction 495 instructionIndex--; 496 numberInstruction(block, op, instructionIndex); 497 final int opId = op.id(); 498 499 try (Indent indent3 = debug.logAndIndent("handle inst %d: %s", opId, op)) { 500 501 /* 502 * Add a temp range for each register if operation destroys 503 * caller-save registers. 504 */ 505 if (op.destroysCallerSavedRegisters()) { 506 for (Register r : callerSaveRegs) { 507 if (allocator.attributes(r).isAllocatable()) { 508 addTemp(r.asValue(), opId, RegisterPriority.None); 509 } 510 } 511 if (debug.isLogEnabled()) { 512 debug.log("operation destroys all caller-save registers"); 513 } 514 } 515 516 op.visitEachOutput(outputConsumer); 517 op.visitEachTemp(tempConsumer); 518 op.visitEachAlive(aliveConsumer); 519 op.visitEachInput(inputConsumer); 520 521 /* 522 * Add uses of live locals from interpreter's point of view for 523 * proper debug information generation. Treat these operands as temp 524 * values (if the live range is extended to a call site, the value 525 * would be in a register at the call otherwise). 526 */ 527 op.visitEachState(stateProc); 528 } 529 530 } // end of instruction iteration 531 // number label instruction 532 instructionIndex--; 533 numberInstruction(block, instructions.get(0), instructionIndex); 534 AbstractBlockBase<?> pred = blockId == 0 ? null : blocks[blockId - 1]; 535 handleBlockBegin(block, pred); 536 } 537 if (debug.isDumpEnabled(DebugContext.VERY_DETAILED_LEVEL)) { 538 allocator.printIntervals("After Block " + block); 539 } 540 } // end of block iteration 541 assert instructionIndex == 0 : "not at start?" + instructionIndex; 542 handleTraceBegin(blocks[0]); 543 544 // fix spill state for phi/incoming intervals 545 for (TraceInterval interval : allocator.intervals()) { 546 if (interval != null && interval.spillState().equals(SpillState.NoDefinitionFound) && interval.spillDefinitionPos() != -1) { 547 // there was a definition in a phi/incoming 548 interval.setSpillState(SpillState.NoSpillStore); 549 } 550 } 551 if (TraceRAuseInterTraceHints.getValue(allocator.getLIR().getOptions())) { 552 addInterTraceHints(); 553 } 554 for (FixedInterval interval1 : allocator.fixedIntervals()) { 555 if (interval1 != null) { 556 /* We use [-1, 0] to avoid intersection with incoming values. */ 557 interval1.addRange(-1, 0); 558 } 559 } 560 } 561 } 562 563 private void handleTraceBegin(AbstractBlockBase<?> block) { 564 LIRInstruction op = getLIR().getLIRforBlock(block).get(0); 565 GlobalLivenessInfo livenessInfo = allocator.getGlobalLivenessInfo(); 566 for (int varNum : livenessInfo.getBlockIn(block)) { 567 if (isAliveAtBlockBegin(varNum)) { 568 addVariableDef(livenessInfo.getVariable(varNum), op, RegisterPriority.None); 569 } 570 } 571 } 572 573 private boolean isAliveAtBlockBegin(int varNum) { 574 return allocator.intervalFor(varNum) != null; 575 } 576 577 private void handleBlockBegin(AbstractBlockBase<?> block, AbstractBlockBase<?> pred) { 578 if (SSAUtil.isMerge(block)) { 579 // handle phis 580 // method parameters are fixed later on (see end of #buildIntervals) 581 LabelOp label = SSAUtil.phiIn(getLIR(), block); 582 JumpOp jump = pred == null ? null : SSAUtil.phiOut(getLIR(), pred); 583 for (int i = 0; i < label.getPhiSize(); i++) { 584 Variable var = asVariable(label.getIncomingValue(i)); 585 TraceInterval toInterval = addVariableDef(var, label, RegisterPriority.ShouldHaveRegister); 586 // set hint for phis 587 if (jump != null) { 588 Value out = jump.getOutgoingValue(i); 589 if (isVariable(out)) { 590 TraceInterval fromInterval = allocator.getOrCreateInterval(asVariable(out)); 591 toInterval.setLocationHint(fromInterval); 592 } 593 } 594 } 595 } 596 } 597 598 private void handleBlockEnd(AbstractBlockBase<?> block, int opId) { 599 // always alive until the end of the block 600 int aliveOpId = opId + 1; 601 GlobalLivenessInfo livenessInfo = allocator.getGlobalLivenessInfo(); 602 for (int varNum : livenessInfo.getBlockOut(block)) { 603 if (allocator.intervalFor(varNum) == null) { 604 addVariableUse(livenessInfo.getVariable(varNum), 0, aliveOpId, RegisterPriority.None); 605 } 606 } 607 } 608 609 private void numberInstruction(AbstractBlockBase<?> block, LIRInstruction op, int index) { 610 int opId = index << 1; 611 assert op.id() == -1 || op.id() == opId : "must match"; 612 op.setId(opId); 613 allocator.putOpIdMaps(index, op, block); 614 assert allocator.instructionForId(opId) == op : "must match"; 615 } 616 617 @SuppressWarnings("try") 618 private void addInterTraceHints() { 619 try (DebugContext.Scope s = debug.scope("InterTraceHints", allocator)) { 620 GlobalLivenessInfo livenessInfo = allocator.getGlobalLivenessInfo(); 621 // set hints for phi/incoming intervals 622 for (AbstractBlockBase<?> block : sortedBlocks()) { 623 LabelOp label = (LabelOp) getLIR().getLIRforBlock(block).get(0); 624 for (AbstractBlockBase<?> pred : block.getPredecessors()) { 625 addInterTraceHints(livenessInfo, pred, block, label); 626 } 627 } 628 } catch (Throwable e) { 629 throw debug.handle(e); 630 } 631 } 632 633 private void addInterTraceHints(GlobalLivenessInfo livenessInfo, AbstractBlockBase<?> from, AbstractBlockBase<?> to, LabelOp label) { 634 if (isAllocated(to, from)) { 635 int[] liveVars = livenessInfo.getBlockIn(to); 636 Value[] outLocation = livenessInfo.getOutLocation(from); 637 638 for (int i = 0; i < liveVars.length; i++) { 639 int varNum = liveVars[i]; 640 TraceInterval toInterval = allocator.intervalFor(varNum); 641 if (toInterval != null && !toInterval.hasHint()) { 642 Value fromValue = outLocation[i]; 643 if (!LIRValueUtil.isConstantValue(fromValue)) { 644 addInterTraceHint(label, varNum, fromValue); 645 } 646 } 647 } 648 } 649 } 650 651 private void addInterTraceHint(LabelOp label, int varNum, Value fromValue) { 652 assert isRegister(fromValue) || isVariable(fromValue) || isStackSlotValue(fromValue) || isShadowedRegisterValue(fromValue) : "Wrong fromValue: " + fromValue; 653 TraceInterval to = allocator.intervalFor(varNum); 654 if (to == null) { 655 // variable not live -> do nothing 656 return; 657 } 658 if (isVariableOrRegister(fromValue)) { 659 IntervalHint from = getIntervalHint((AllocatableValue) fromValue); 660 setHint(label, to, from, debug); 661 } else if (isStackSlotValue(fromValue)) { 662 setSpillSlot(label, to, (AllocatableValue) fromValue, debug); 663 } else if (TraceRAshareSpillInformation.getValue(allocator.getLIR().getOptions()) && isShadowedRegisterValue(fromValue)) { 664 ShadowedRegisterValue shadowedRegisterValue = asShadowedRegisterValue(fromValue); 665 IntervalHint from = getIntervalHint(shadowedRegisterValue.getRegister()); 666 setHint(label, to, from, debug); 667 setSpillSlot(label, to, shadowedRegisterValue.getStackSlot(), debug); 668 } else { 669 throw GraalError.shouldNotReachHere(); 670 } 671 } 672 673 private static void setHint(final LIRInstruction op, TraceInterval to, IntervalHint from, DebugContext debug) { 674 IntervalHint currentHint = to.locationHint(false); 675 if (currentHint == null) { 676 /* 677 * Update hint if there was none or if the hint interval starts after the hinted 678 * interval. 679 */ 680 to.setLocationHint(from); 681 if (debug.isLogEnabled()) { 682 debug.log("operation at opId %d: added hint from interval %s to %s", op.id(), from, to); 683 } 684 } 685 } 686 687 private static void setSpillSlot(LIRInstruction op, TraceInterval interval, AllocatableValue spillSlot, DebugContext debug) { 688 if (interval.spillSlot() == null) { 689 interval.setSpillSlot(spillSlot); 690 interval.setSpillState(SpillState.StartInMemory); 691 if (debug.isLogEnabled()) { 692 debug.log("operation at opId %d: added spill slot %s to interval %s", op.id(), spillSlot, interval); 693 } 694 } else if (debug.isLogEnabled()) { 695 debug.log("operation at opId %d: has already a slot assigned %s", op.id(), interval.spillSlot()); 696 } 697 } 698 699 private IntervalHint getIntervalHint(AllocatableValue from) { 700 if (isRegister(from)) { 701 return allocator.getOrCreateFixedInterval(asRegisterValue(from)); 702 } 703 return allocator.getOrCreateInterval(asVariable(from)); 704 } 705 706 } 707 708 /** 709 * Returns a value for a interval definition, which can be used for re-materialization. 710 * 711 * @param op An instruction which defines a value 712 * @param operand The destination operand of the instruction 713 * @param interval The interval for this defined value. 714 * @return Returns the value which is moved to the instruction and which can be reused at all 715 * reload-locations in case the interval of this instruction is spilled. Currently this 716 * can only be a {@link JavaConstant}. 717 */ 718 private static JavaConstant getMaterializedValue(LIRInstruction op, Value operand, TraceInterval interval, boolean neverSpillConstants, MoveFactory spillMoveFactory) { 719 if (LoadConstantOp.isLoadConstantOp(op)) { 720 LoadConstantOp move = LoadConstantOp.asLoadConstantOp(op); 721 if (move.getConstant() instanceof JavaConstant) { 722 if (!neverSpillConstants) { 723 if (!spillMoveFactory.allowConstantToStackMove(move.getConstant())) { 724 return null; 725 } 726 /* 727 * Check if the interval has any uses which would accept an stack location 728 * (priority == ShouldHaveRegister). Rematerialization of such intervals can 729 * result in a degradation, because rematerialization always inserts a constant 730 * load, even if the value is not needed in a register. 731 */ 732 int numUsePos = interval.numUsePos(); 733 for (int useIdx = 0; useIdx < numUsePos; useIdx++) { 734 TraceInterval.RegisterPriority priority = interval.getUsePosRegisterPriority(useIdx); 735 if (priority == TraceInterval.RegisterPriority.ShouldHaveRegister) { 736 return null; 737 } 738 } 739 } 740 return (JavaConstant) move.getConstant(); 741 } 742 } 743 return null; 744 } 745 746} 747