Mercurial > hg > truffle
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() { |