comparison graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScan.java @ 21320:26beac81ab2f

LinearScan: encapsulate assignLocations().
author Josef Eisl <josef.eisl@jku.at>
date Tue, 12 May 2015 10:36:01 +0200
parents 9ddb5a749eab
children 1d5955a59d47
comparison
equal deleted inserted replaced
21319:9ddb5a749eab 21320:26beac81ab2f
1016 } 1016 }
1017 1017
1018 } 1018 }
1019 } 1019 }
1020 1020
1021 // * Phase 7: assign register numbers back to LIR
1022 // (includes computation of debug information and oop maps)
1023
1024 static StackSlotValue canonicalSpillOpr(Interval interval) { 1021 static StackSlotValue canonicalSpillOpr(Interval interval) {
1025 assert interval.spillSlot() != null : "canonical spill slot not set"; 1022 assert interval.spillSlot() != null : "canonical spill slot not set";
1026 return interval.spillSlot(); 1023 return interval.spillSlot();
1027 }
1028
1029 /**
1030 * Assigns the allocated location for an LIR instruction operand back into the instruction.
1031 *
1032 * @param operand an LIR instruction operand
1033 * @param opId the id of the LIR instruction using {@code operand}
1034 * @param mode the usage mode for {@code operand} by the instruction
1035 * @return the location assigned for the operand
1036 */
1037 private Value colorLirOperand(Variable operand, int opId, OperandMode mode) {
1038 Interval interval = intervalFor(operand);
1039 assert interval != null : "interval must exist";
1040
1041 if (opId != -1) {
1042 if (DetailedAsserts.getValue()) {
1043 AbstractBlockBase<?> block = blockForId(opId);
1044 if (block.getSuccessorCount() <= 1 && opId == getLastLirInstructionId(block)) {
1045 /*
1046 * Check if spill moves could have been appended at the end of this block, but
1047 * before the branch instruction. So the split child information for this branch
1048 * would be incorrect.
1049 */
1050 LIRInstruction instr = ir.getLIRforBlock(block).get(ir.getLIRforBlock(block).size() - 1);
1051 if (instr instanceof StandardOp.JumpOp) {
1052 if (blockData.get(block).liveOut.get(operandNumber(operand))) {
1053 assert false : String.format(
1054 "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",
1055 block, instr, operand);
1056 }
1057 }
1058 }
1059 }
1060
1061 /*
1062 * Operands are not changed when an interval is split during allocation, so search the
1063 * right interval here.
1064 */
1065 interval = splitChildAtOpId(interval, opId, mode);
1066 }
1067
1068 if (isIllegal(interval.location()) && interval.canMaterialize()) {
1069 assert mode != OperandMode.DEF;
1070 return interval.getMaterializedValue();
1071 }
1072 return interval.location();
1073 } 1024 }
1074 1025
1075 private boolean isMaterialized(AllocatableValue operand, int opId, OperandMode mode) { 1026 private boolean isMaterialized(AllocatableValue operand, int opId, OperandMode mode) {
1076 Interval interval = intervalFor(operand); 1027 Interval interval = intervalFor(operand);
1077 assert interval != null : "interval must exist"; 1028 assert interval != null : "interval must exist";
1106 1057
1107 private boolean isCallerSave(Value operand) { 1058 private boolean isCallerSave(Value operand) {
1108 return attributes(asRegister(operand)).isCallerSave(); 1059 return attributes(asRegister(operand)).isCallerSave();
1109 } 1060 }
1110 1061
1111 /** 1062 /** Phase 7: assign register numbers back to LIR */
1112 * @param op 1063 private final class AssignLocations extends AllocationPhase {
1113 * @param operand 1064
1114 * @param valueMode 1065 @Override
1115 * @param flags 1066 protected <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder,
1116 * @see InstructionValueProcedure#doValue(LIRInstruction, Value, OperandMode, EnumSet) 1067 SpillMoveFactory spillMoveFactory) {
1117 */ 1068 assignLocations();
1118 private Value debugInfoProcedure(LIRInstruction op, Value operand, OperandMode valueMode, EnumSet<OperandFlag> flags) { 1069 }
1119 if (isVirtualStackSlot(operand)) { 1070
1120 return operand; 1071 /**
1121 } 1072 * Assigns the allocated location for an LIR instruction operand back into the instruction.
1122 int tempOpId = op.id(); 1073 *
1123 OperandMode mode = OperandMode.USE; 1074 * @param operand an LIR instruction operand
1124 AbstractBlockBase<?> block = blockForId(tempOpId); 1075 * @param opId the id of the LIR instruction using {@code operand}
1125 if (block.getSuccessorCount() == 1 && tempOpId == getLastLirInstructionId(block)) { 1076 * @param mode the usage mode for {@code operand} by the instruction
1077 * @return the location assigned for the operand
1078 */
1079 private Value colorLirOperand(Variable operand, int opId, OperandMode mode) {
1080 Interval interval = intervalFor(operand);
1081 assert interval != null : "interval must exist";
1082
1083 if (opId != -1) {
1084 if (DetailedAsserts.getValue()) {
1085 AbstractBlockBase<?> block = blockForId(opId);
1086 if (block.getSuccessorCount() <= 1 && opId == getLastLirInstructionId(block)) {
1087 /*
1088 * Check if spill moves could have been appended at the end of this block,
1089 * but before the branch instruction. So the split child information for
1090 * this branch would be incorrect.
1091 */
1092 LIRInstruction instr = ir.getLIRforBlock(block).get(ir.getLIRforBlock(block).size() - 1);
1093 if (instr instanceof StandardOp.JumpOp) {
1094 if (blockData.get(block).liveOut.get(operandNumber(operand))) {
1095 assert false : String.format(
1096 "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",
1097 block, instr, operand);
1098 }
1099 }
1100 }
1101 }
1102
1103 /*
1104 * Operands are not changed when an interval is split during allocation, so search
1105 * the right interval here.
1106 */
1107 interval = splitChildAtOpId(interval, opId, mode);
1108 }
1109
1110 if (isIllegal(interval.location()) && interval.canMaterialize()) {
1111 assert mode != OperandMode.DEF;
1112 return interval.getMaterializedValue();
1113 }
1114 return interval.location();
1115 }
1116
1117 /**
1118 * @param op
1119 * @param operand
1120 * @param valueMode
1121 * @param flags
1122 * @see InstructionValueProcedure#doValue(LIRInstruction, Value, OperandMode, EnumSet)
1123 */
1124 private Value debugInfoProcedure(LIRInstruction op, Value operand, OperandMode valueMode, EnumSet<OperandFlag> flags) {
1125 if (isVirtualStackSlot(operand)) {
1126 return operand;
1127 }
1128 int tempOpId = op.id();
1129 OperandMode mode = OperandMode.USE;
1130 AbstractBlockBase<?> block = blockForId(tempOpId);
1131 if (block.getSuccessorCount() == 1 && tempOpId == getLastLirInstructionId(block)) {
1132 /*
1133 * Generating debug information for the last instruction of a block. If this
1134 * instruction is a branch, spill moves are inserted before this branch and so the
1135 * wrong operand would be returned (spill moves at block boundaries are not
1136 * considered in the live ranges of intervals).
1137 *
1138 * Solution: use the first opId of the branch target block instead.
1139 */
1140 final LIRInstruction instr = ir.getLIRforBlock(block).get(ir.getLIRforBlock(block).size() - 1);
1141 if (instr instanceof StandardOp.JumpOp) {
1142 if (blockData.get(block).liveOut.get(operandNumber(operand))) {
1143 tempOpId = getFirstLirInstructionId(block.getSuccessors().iterator().next());
1144 mode = OperandMode.DEF;
1145 }
1146 }
1147 }
1148
1126 /* 1149 /*
1127 * Generating debug information for the last instruction of a block. If this instruction 1150 * Get current location of operand. The operand must be live because debug information
1128 * is a branch, spill moves are inserted before this branch and so the wrong operand 1151 * is considered when building the intervals if the interval is not live,
1129 * would be returned (spill moves at block boundaries are not considered in the live 1152 * colorLirOperand will cause an assert on failure.
1130 * ranges of intervals).
1131 *
1132 * Solution: use the first opId of the branch target block instead.
1133 */ 1153 */
1134 final LIRInstruction instr = ir.getLIRforBlock(block).get(ir.getLIRforBlock(block).size() - 1); 1154 Value result = colorLirOperand((Variable) operand, tempOpId, mode);
1135 if (instr instanceof StandardOp.JumpOp) { 1155 assert !hasCall(tempOpId) || isStackSlotValue(result) || isConstant(result) || !isCallerSave(result) : "cannot have caller-save register operands at calls";
1136 if (blockData.get(block).liveOut.get(operandNumber(operand))) { 1156 return result;
1137 tempOpId = getFirstLirInstructionId(block.getSuccessors().iterator().next()); 1157 }
1138 mode = OperandMode.DEF; 1158
1139 } 1159 private void computeDebugInfo(final LIRInstruction op, LIRFrameState info) {
1140 } 1160 info.forEachState(op, this::debugInfoProcedure);
1141 } 1161 }
1142 1162
1143 /* 1163 private void assignLocations(List<LIRInstruction> instructions) {
1144 * Get current location of operand. The operand must be live because debug information is 1164 int numInst = instructions.size();
1145 * considered when building the intervals if the interval is not live, colorLirOperand will 1165 boolean hasDead = false;
1146 * cause an assert on failure. 1166
1147 */ 1167 InstructionValueProcedure assignProc = (op, operand, mode, flags) -> isVariable(operand) ? colorLirOperand((Variable) operand, op.id(), mode) : operand;
1148 Value result = colorLirOperand((Variable) operand, tempOpId, mode); 1168 for (int j = 0; j < numInst; j++) {
1149 assert !hasCall(tempOpId) || isStackSlotValue(result) || isConstant(result) || !isCallerSave(result) : "cannot have caller-save register operands at calls"; 1169 final LIRInstruction op = instructions.get(j);
1150 return result; 1170 if (op == null) {
1151 }
1152
1153 private void computeDebugInfo(final LIRInstruction op, LIRFrameState info) {
1154 info.forEachState(op, this::debugInfoProcedure);
1155 }
1156
1157 private void assignLocations(List<LIRInstruction> instructions) {
1158 int numInst = instructions.size();
1159 boolean hasDead = false;
1160
1161 InstructionValueProcedure assignProc = (op, operand, mode, flags) -> isVariable(operand) ? colorLirOperand((Variable) operand, op.id(), mode) : operand;
1162 for (int j = 0; j < numInst; j++) {
1163 final LIRInstruction op = instructions.get(j);
1164 if (op == null) { // this can happen when spill-moves are removed in eliminateSpillMoves
1165 hasDead = true;
1166 continue;
1167 }
1168
1169 // remove useless moves
1170 MoveOp move = null;
1171 if (op instanceof MoveOp) {
1172 move = (MoveOp) op;
1173 AllocatableValue result = move.getResult();
1174 if (isVariable(result) && isMaterialized(result, op.id(), OperandMode.DEF)) {
1175 /* 1171 /*
1176 * This happens if a materializable interval is originally not spilled but then 1172 * this can happen when spill-moves are removed in eliminateSpillMoves
1177 * kicked out in LinearScanWalker.splitForSpilling(). When kicking out such an
1178 * interval this move operation was already generated.
1179 */ 1173 */
1180 instructions.set(j, null);
1181 hasDead = true; 1174 hasDead = true;
1182 continue; 1175 continue;
1183 } 1176 }
1184 } 1177
1185 1178 // remove useless moves
1186 op.forEachInput(assignProc); 1179 MoveOp move = null;
1187 op.forEachAlive(assignProc); 1180 if (op instanceof MoveOp) {
1188 op.forEachTemp(assignProc); 1181 move = (MoveOp) op;
1189 op.forEachOutput(assignProc); 1182 AllocatableValue result = move.getResult();
1190 1183 if (isVariable(result) && isMaterialized(result, op.id(), OperandMode.DEF)) {
1191 // compute reference map and debug information 1184 /*
1192 op.forEachState((inst, state) -> computeDebugInfo(inst, state)); 1185 * This happens if a materializable interval is originally not spilled but
1193 1186 * then kicked out in LinearScanWalker.splitForSpilling(). When kicking out
1194 // remove useless moves 1187 * such an interval this move operation was already generated.
1195 if (move != null) { 1188 */
1196 if (move.getInput().equals(move.getResult())) { 1189 instructions.set(j, null);
1197 instructions.set(j, null); 1190 hasDead = true;
1198 hasDead = true; 1191 continue;
1199 } 1192 }
1200 } 1193 }
1201 } 1194
1202 1195 op.forEachInput(assignProc);
1203 if (hasDead) { 1196 op.forEachAlive(assignProc);
1204 // Remove null values from the list. 1197 op.forEachTemp(assignProc);
1205 instructions.removeAll(Collections.singleton(null)); 1198 op.forEachOutput(assignProc);
1206 } 1199
1207 } 1200 // compute reference map and debug information
1208 1201 op.forEachState((inst, state) -> computeDebugInfo(inst, state));
1209 private void assignLocations() { 1202
1210 try (Indent indent = Debug.logAndIndent("assign locations")) { 1203 // remove useless moves
1211 for (AbstractBlockBase<?> block : sortedBlocks) { 1204 if (move != null) {
1212 try (Indent indent2 = Debug.logAndIndent("assign locations in block B%d", block.getId())) { 1205 if (move.getInput().equals(move.getResult())) {
1213 assignLocations(ir.getLIRforBlock(block)); 1206 instructions.set(j, null);
1207 hasDead = true;
1208 }
1209 }
1210 }
1211
1212 if (hasDead) {
1213 // Remove null values from the list.
1214 instructions.removeAll(Collections.singleton(null));
1215 }
1216 }
1217
1218 private void assignLocations() {
1219 try (Indent indent = Debug.logAndIndent("assign locations")) {
1220 for (AbstractBlockBase<?> block : sortedBlocks) {
1221 try (Indent indent2 = Debug.logAndIndent("assign locations in block B%d", block.getId())) {
1222 assignLocations(ir.getLIRforBlock(block));
1223 }
1214 } 1224 }
1215 } 1225 }
1216 } 1226 }
1217 } 1227 }
1218 1228
1290 @Override 1300 @Override
1291 protected <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, 1301 protected <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder,
1292 SpillMoveFactory spillMoveFactory) { 1302 SpillMoveFactory spillMoveFactory) {
1293 beforeSpillMoveElimination(); 1303 beforeSpillMoveElimination();
1294 eliminateSpillMoves(); 1304 eliminateSpillMoves();
1295 }
1296
1297 }
1298
1299 private final class AssignLocations extends AllocationPhase {
1300
1301 @Override
1302 protected <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder,
1303 SpillMoveFactory spillMoveFactory) {
1304 assignLocations();
1305 } 1305 }
1306 1306
1307 } 1307 }
1308 1308
1309 protected void beforeSpillMoveElimination() { 1309 protected void beforeSpillMoveElimination() {