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 jdk.internal.jvmci.code.ValueUtil.*; 028 029import java.util.*; 030 031import jdk.internal.jvmci.code.*; 032import com.oracle.graal.debug.*; 033import jdk.internal.jvmci.meta.*; 034 035import com.oracle.graal.compiler.common.alloc.*; 036import com.oracle.graal.compiler.common.cfg.*; 037import com.oracle.graal.lir.*; 038import com.oracle.graal.lir.LIRInstruction.OperandFlag; 039import com.oracle.graal.lir.LIRInstruction.OperandMode; 040import com.oracle.graal.lir.StandardOp.MoveOp; 041import com.oracle.graal.lir.gen.*; 042import com.oracle.graal.lir.gen.LIRGeneratorTool.SpillMoveFactory; 043import com.oracle.graal.lir.phases.*; 044 045/** 046 * Phase 7: Assign register numbers back to LIR. 047 */ 048public final class LinearScanAssignLocationsPhase extends AllocationPhase { 049 050 private final LinearScan allocator; 051 052 LinearScanAssignLocationsPhase(LinearScan allocator) { 053 this.allocator = allocator; 054 } 055 056 @Override 057 protected <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, SpillMoveFactory spillMoveFactory, 058 RegisterAllocationConfig registerAllocationConfig) { 059 assignLocations(); 060 } 061 062 /** 063 * Assigns the allocated location for an LIR instruction operand back into the instruction. 064 * 065 * @param operand an LIR instruction operand 066 * @param opId the id of the LIR instruction using {@code operand} 067 * @param mode the usage mode for {@code operand} by the instruction 068 * @return the location assigned for the operand 069 */ 070 private Value colorLirOperand(Variable operand, int opId, OperandMode mode) { 071 Interval interval = allocator.intervalFor(operand); 072 assert interval != null : "interval must exist"; 073 074 if (opId != -1) { 075 if (DetailedAsserts.getValue()) { 076 AbstractBlockBase<?> block = allocator.blockForId(opId); 077 if (block.getSuccessorCount() <= 1 && opId == allocator.getLastLirInstructionId(block)) { 078 /* 079 * Check if spill moves could have been appended at the end of this block, but 080 * before the branch instruction. So the split child information for this branch 081 * would be incorrect. 082 */ 083 LIRInstruction instr = allocator.getLIR().getLIRforBlock(block).get(allocator.getLIR().getLIRforBlock(block).size() - 1); 084 if (instr instanceof StandardOp.JumpOp) { 085 if (allocator.getBlockData(block).liveOut.get(allocator.operandNumber(operand))) { 086 assert false : String.format( 087 "can't get split child for the last branch of a block because the information would be incorrect (moves are inserted before the branch in resolveDataFlow) block=%s, instruction=%s, operand=%s", 088 block, instr, operand); 089 } 090 } 091 } 092 } 093 094 /* 095 * Operands are not changed when an interval is split during allocation, so search the 096 * right interval here. 097 */ 098 interval = allocator.splitChildAtOpId(interval, opId, mode); 099 } 100 101 if (isIllegal(interval.location()) && interval.canMaterialize()) { 102 assert mode != OperandMode.DEF; 103 return interval.getMaterializedValue(); 104 } 105 return interval.location(); 106 } 107 108 /** 109 * @param op 110 * @param operand 111 * @param valueMode 112 * @param flags 113 * @see InstructionValueProcedure#doValue(LIRInstruction, Value, OperandMode, EnumSet) 114 */ 115 private Value debugInfoProcedure(LIRInstruction op, Value operand, OperandMode valueMode, EnumSet<OperandFlag> flags) { 116 if (isVirtualStackSlot(operand)) { 117 return operand; 118 } 119 int tempOpId = op.id(); 120 OperandMode mode = OperandMode.USE; 121 AbstractBlockBase<?> block = allocator.blockForId(tempOpId); 122 if (block.getSuccessorCount() == 1 && tempOpId == allocator.getLastLirInstructionId(block)) { 123 /* 124 * Generating debug information for the last instruction of a block. If this instruction 125 * is a branch, spill moves are inserted before this branch and so the wrong operand 126 * would be returned (spill moves at block boundaries are not considered in the live 127 * ranges of intervals). 128 * 129 * Solution: use the first opId of the branch target block instead. 130 */ 131 final LIRInstruction instr = allocator.getLIR().getLIRforBlock(block).get(allocator.getLIR().getLIRforBlock(block).size() - 1); 132 if (instr instanceof StandardOp.JumpOp) { 133 if (allocator.getBlockData(block).liveOut.get(allocator.operandNumber(operand))) { 134 tempOpId = allocator.getFirstLirInstructionId(block.getSuccessors().iterator().next()); 135 mode = OperandMode.DEF; 136 } 137 } 138 } 139 140 /* 141 * Get current location of operand. The operand must be live because debug information is 142 * considered when building the intervals if the interval is not live, colorLirOperand will 143 * cause an assert on failure. 144 */ 145 Value result = colorLirOperand((Variable) operand, tempOpId, mode); 146 assert !allocator.hasCall(tempOpId) || isStackSlotValue(result) || isConstant(result) || !allocator.isCallerSave(result) : "cannot have caller-save register operands at calls"; 147 return result; 148 } 149 150 private void computeDebugInfo(final LIRInstruction op, LIRFrameState info) { 151 info.forEachState(op, this::debugInfoProcedure); 152 } 153 154 private void assignLocations(List<LIRInstruction> instructions) { 155 int numInst = instructions.size(); 156 boolean hasDead = false; 157 158 InstructionValueProcedure assignProc = (op, operand, mode, flags) -> isVariable(operand) ? colorLirOperand((Variable) operand, op.id(), mode) : operand; 159 for (int j = 0; j < numInst; j++) { 160 final LIRInstruction op = instructions.get(j); 161 if (op == null) { 162 /* 163 * this can happen when spill-moves are removed in eliminateSpillMoves 164 */ 165 hasDead = true; 166 continue; 167 } 168 169 // remove useless moves 170 MoveOp move = null; 171 if (op instanceof MoveOp) { 172 move = (MoveOp) op; 173 AllocatableValue result = move.getResult(); 174 if (isVariable(result) && allocator.isMaterialized(result, op.id(), OperandMode.DEF)) { 175 /* 176 * This happens if a materializable interval is originally not spilled but then 177 * kicked out in LinearScanWalker.splitForSpilling(). When kicking out such an 178 * interval this move operation was already generated. 179 */ 180 instructions.set(j, null); 181 hasDead = true; 182 continue; 183 } 184 } 185 186 op.forEachInput(assignProc); 187 op.forEachAlive(assignProc); 188 op.forEachTemp(assignProc); 189 op.forEachOutput(assignProc); 190 191 // compute reference map and debug information 192 op.forEachState((inst, state) -> computeDebugInfo(inst, state)); 193 194 // remove useless moves 195 if (move != null) { 196 if (move.getInput().equals(move.getResult())) { 197 instructions.set(j, null); 198 hasDead = true; 199 } 200 } 201 } 202 203 if (hasDead) { 204 // Remove null values from the list. 205 instructions.removeAll(Collections.singleton(null)); 206 } 207 } 208 209 private void assignLocations() { 210 try (Indent indent = Debug.logAndIndent("assign locations")) { 211 for (AbstractBlockBase<?> block : allocator.sortedBlocks()) { 212 try (Indent indent2 = Debug.logAndIndent("assign locations in block B%d", block.getId())) { 213 assignLocations(allocator.getLIR().getLIRforBlock(block)); 214 } 215 } 216 } 217 } 218}