Mercurial > hg > truffle
comparison graal/com.oracle.graal.lir/src/com/oracle/graal/lir/constopt/ConstantLoadOptimization.java @ 19214:e1f63e69dc6c
Make ConstantLoadOptimization a LowLevelHighTierPhase.
author | Josef Eisl <josef.eisl@jku.at> |
---|---|
date | Mon, 09 Feb 2015 09:10:44 +0100 |
parents | ecb9d0cedbab |
children | edd93c34d015 |
comparison
equal
deleted
inserted
replaced
19213:d7e743760000 | 19214:e1f63e69dc6c |
---|---|
25 import static com.oracle.graal.api.code.ValueUtil.*; | 25 import static com.oracle.graal.api.code.ValueUtil.*; |
26 import static com.oracle.graal.lir.LIRValueUtil.*; | 26 import static com.oracle.graal.lir.LIRValueUtil.*; |
27 | 27 |
28 import java.util.*; | 28 import java.util.*; |
29 | 29 |
30 import com.oracle.graal.api.code.*; | |
30 import com.oracle.graal.api.meta.*; | 31 import com.oracle.graal.api.meta.*; |
31 import com.oracle.graal.compiler.common.cfg.*; | 32 import com.oracle.graal.compiler.common.cfg.*; |
32 import com.oracle.graal.debug.*; | 33 import com.oracle.graal.debug.*; |
33 import com.oracle.graal.debug.Debug.Scope; | 34 import com.oracle.graal.debug.Debug.Scope; |
34 import com.oracle.graal.lir.*; | 35 import com.oracle.graal.lir.*; |
36 import com.oracle.graal.lir.LIRInstruction.OperandMode; | 37 import com.oracle.graal.lir.LIRInstruction.OperandMode; |
37 import com.oracle.graal.lir.StandardOp.MoveOp; | 38 import com.oracle.graal.lir.StandardOp.MoveOp; |
38 import com.oracle.graal.lir.constopt.ConstantTree.Flags; | 39 import com.oracle.graal.lir.constopt.ConstantTree.Flags; |
39 import com.oracle.graal.lir.constopt.ConstantTree.NodeCost; | 40 import com.oracle.graal.lir.constopt.ConstantTree.NodeCost; |
40 import com.oracle.graal.lir.gen.*; | 41 import com.oracle.graal.lir.gen.*; |
42 import com.oracle.graal.lir.phases.*; | |
41 import com.oracle.graal.options.*; | 43 import com.oracle.graal.options.*; |
42 | 44 |
43 /** | 45 /** |
44 * This optimization tries to improve the handling of constants by replacing a single definition of | 46 * This optimization tries to improve the handling of constants by replacing a single definition of |
45 * a constant, which is potentially scheduled into a block with high probability, with one or more | 47 * a constant, which is potentially scheduled into a block with high probability, with one or more |
46 * definitions in blocks with a lower probability. | 48 * definitions in blocks with a lower probability. |
47 */ | 49 */ |
48 public final class ConstantLoadOptimization { | 50 public final class ConstantLoadOptimization extends LowLevelHighTierPhase { |
49 | 51 |
50 public static class Options { | 52 public static class Options { |
51 // @formatter:off | 53 // @formatter:off |
52 @Option(help = "Enable constant load optimization.", type = OptionType.Debug) | 54 @Option(help = "Enable constant load optimization.", type = OptionType.Debug) |
53 public static final OptionValue<Boolean> ConstantLoadOptimization = new OptionValue<>(true); | 55 public static final OptionValue<Boolean> ConstantLoadOptimization = new OptionValue<>(true); |
54 // @formatter:on | 56 // @formatter:on |
55 } | 57 } |
56 | 58 |
57 public static void optimize(LIR lir, LIRGeneratorTool lirGen) { | 59 @Override |
58 new ConstantLoadOptimization(lir, lirGen).apply(); | 60 protected void run(TargetDescription target, LIRGenerationResult lirGenRes, LIRGeneratorTool lirGen) { |
61 new Optimization(lirGenRes.getLIR(), lirGen).apply(); | |
59 } | 62 } |
60 | |
61 private LIR lir; | |
62 private LIRGeneratorTool lirGen; | |
63 private VariableMap<DefUseTree> map; | |
64 private BitSet phiConstants; | |
65 private BitSet defined; | |
66 private BlockMap<List<UseEntry>> blockMap; | |
67 private BlockMap<LIRInsertionBuffer> insertionBuffers; | |
68 | 63 |
69 private static final DebugMetric constantsTotal = Debug.metric("ConstantLoadOptimization[total]"); | 64 private static final DebugMetric constantsTotal = Debug.metric("ConstantLoadOptimization[total]"); |
70 private static final DebugMetric phiConstantsSkipped = Debug.metric("ConstantLoadOptimization[PhisSkipped]"); | 65 private static final DebugMetric phiConstantsSkipped = Debug.metric("ConstantLoadOptimization[PhisSkipped]"); |
71 private static final DebugMetric singleUsageConstantsSkipped = Debug.metric("ConstantLoadOptimization[SingleUsageSkipped]"); | 66 private static final DebugMetric singleUsageConstantsSkipped = Debug.metric("ConstantLoadOptimization[SingleUsageSkipped]"); |
72 private static final DebugMetric usageAtDefinitionSkipped = Debug.metric("ConstantLoadOptimization[UsageAtDefinitionSkipped]"); | 67 private static final DebugMetric usageAtDefinitionSkipped = Debug.metric("ConstantLoadOptimization[UsageAtDefinitionSkipped]"); |
73 private static final DebugMetric materializeAtDefinitionSkipped = Debug.metric("ConstantLoadOptimization[MaterializeAtDefinitionSkipped]"); | 68 private static final DebugMetric materializeAtDefinitionSkipped = Debug.metric("ConstantLoadOptimization[MaterializeAtDefinitionSkipped]"); |
74 private static final DebugMetric constantsOptimized = Debug.metric("ConstantLoadOptimization[optimized]"); | 69 private static final DebugMetric constantsOptimized = Debug.metric("ConstantLoadOptimization[optimized]"); |
75 | 70 |
76 private ConstantLoadOptimization(LIR lir, LIRGeneratorTool lirGen) { | 71 private static final class Optimization { |
77 this.lir = lir; | 72 private final LIR lir; |
78 this.lirGen = lirGen; | 73 private final LIRGeneratorTool lirGen; |
79 this.map = new VariableMap<>(); | 74 private final VariableMap<DefUseTree> map; |
80 this.phiConstants = new BitSet(); | 75 private final BitSet phiConstants; |
81 this.defined = new BitSet(); | 76 private final BitSet defined; |
82 this.insertionBuffers = new BlockMap<>(lir.getControlFlowGraph()); | 77 private final BlockMap<List<UseEntry>> blockMap; |
83 this.blockMap = new BlockMap<>(lir.getControlFlowGraph()); | 78 private final BlockMap<LIRInsertionBuffer> insertionBuffers; |
84 } | 79 |
85 | 80 private Optimization(LIR lir, LIRGeneratorTool lirGen) { |
86 private void apply() { | 81 this.lir = lir; |
87 try (Indent indent = Debug.logAndIndent("ConstantLoadOptimization")) { | 82 this.lirGen = lirGen; |
88 try (Scope s = Debug.scope("BuildDefUseTree")) { | 83 this.map = new VariableMap<>(); |
89 // build DefUseTree | 84 this.phiConstants = new BitSet(); |
90 lir.getControlFlowGraph().getBlocks().forEach(this::analyzeBlock); | 85 this.defined = new BitSet(); |
91 // remove all with only one use | 86 this.insertionBuffers = new BlockMap<>(lir.getControlFlowGraph()); |
92 map.filter(t -> { | 87 this.blockMap = new BlockMap<>(lir.getControlFlowGraph()); |
93 if (t.usageCount() > 1) { | 88 } |
94 return true; | 89 |
95 } else { | 90 private void apply() { |
96 singleUsageConstantsSkipped.increment(); | 91 try (Indent indent = Debug.logAndIndent("ConstantLoadOptimization")) { |
97 return false; | 92 try (Scope s = Debug.scope("BuildDefUseTree")) { |
98 } | 93 // build DefUseTree |
99 }); | 94 lir.getControlFlowGraph().getBlocks().forEach(this::analyzeBlock); |
100 // collect block map | 95 // remove all with only one use |
101 map.forEach(tree -> tree.forEach(this::addUsageToBlockMap)); | 96 map.filter(t -> { |
102 } catch (Throwable e) { | 97 if (t.usageCount() > 1) { |
103 throw Debug.handle(e); | 98 return true; |
104 } | 99 } else { |
105 | 100 singleUsageConstantsSkipped.increment(); |
106 try (Scope s = Debug.scope("BuildConstantTree")) { | 101 return false; |
107 // create ConstantTree | 102 } |
108 map.forEach(this::createConstantTree); | 103 }); |
109 | 104 // collect block map |
110 // insert moves, delete null instructions and reset instruction ids | 105 map.forEach(tree -> tree.forEach(this::addUsageToBlockMap)); |
111 lir.getControlFlowGraph().getBlocks().forEach(this::rewriteBlock); | 106 } catch (Throwable e) { |
112 | 107 throw Debug.handle(e); |
113 assert verifyStates(); | 108 } |
114 } catch (Throwable e) { | 109 |
115 throw Debug.handle(e); | 110 try (Scope s = Debug.scope("BuildConstantTree")) { |
116 } | 111 // create ConstantTree |
117 } | 112 map.forEach(this::createConstantTree); |
118 } | 113 |
119 | 114 // insert moves, delete null instructions and reset instruction ids |
120 private boolean verifyStates() { | 115 lir.getControlFlowGraph().getBlocks().forEach(this::rewriteBlock); |
121 map.forEach(this::verifyStateUsage); | 116 |
122 return true; | 117 assert verifyStates(); |
123 } | 118 } catch (Throwable e) { |
124 | 119 throw Debug.handle(e); |
125 private void verifyStateUsage(DefUseTree tree) { | 120 } |
126 Variable var = tree.getVariable(); | 121 } |
127 ValueConsumer stateConsumer = new ValueConsumer() { | 122 } |
128 | 123 |
129 @Override | 124 private boolean verifyStates() { |
130 public void visitValue(Value operand, OperandMode mode, EnumSet<OperandFlag> flags) { | 125 map.forEach(this::verifyStateUsage); |
131 assert !operand.equals(var) : "constant usage through variable in frame state " + var; | 126 return true; |
132 } | 127 } |
133 }; | 128 |
134 for (AbstractBlock<?> block : lir.getControlFlowGraph().getBlocks()) { | 129 private void verifyStateUsage(DefUseTree tree) { |
135 for (LIRInstruction inst : lir.getLIRforBlock(block)) { | 130 Variable var = tree.getVariable(); |
136 // set instruction id to the index in the lir instruction list | 131 ValueConsumer stateConsumer = new ValueConsumer() { |
137 inst.visitEachState(stateConsumer); | 132 |
138 } | 133 @Override |
139 } | 134 public void visitValue(Value operand, OperandMode mode, EnumSet<OperandFlag> flags) { |
140 } | 135 assert !operand.equals(var) : "constant usage through variable in frame state " + var; |
141 | 136 } |
142 private static boolean isConstantLoad(LIRInstruction inst) { | 137 }; |
143 if (!(inst instanceof MoveOp)) { | 138 for (AbstractBlock<?> block : lir.getControlFlowGraph().getBlocks()) { |
144 return false; | 139 for (LIRInstruction inst : lir.getLIRforBlock(block)) { |
145 } | 140 // set instruction id to the index in the lir instruction list |
146 MoveOp move = (MoveOp) inst; | 141 inst.visitEachState(stateConsumer); |
147 return isConstant(move.getInput()) && isVariable(move.getResult()); | 142 } |
148 } | 143 } |
149 | 144 } |
150 private void addUsageToBlockMap(UseEntry entry) { | 145 |
151 AbstractBlock<?> block = entry.getBlock(); | 146 private static boolean isConstantLoad(LIRInstruction inst) { |
152 List<UseEntry> list = blockMap.get(block); | 147 if (!(inst instanceof MoveOp)) { |
153 if (list == null) { | 148 return false; |
154 list = new ArrayList<>(); | 149 } |
155 blockMap.put(block, list); | 150 MoveOp move = (MoveOp) inst; |
156 } | 151 return isConstant(move.getInput()) && isVariable(move.getResult()); |
157 list.add(entry); | 152 } |
158 } | 153 |
159 | 154 private void addUsageToBlockMap(UseEntry entry) { |
160 /** | 155 AbstractBlock<?> block = entry.getBlock(); |
161 * Collects def-use information for a {@code block}. | 156 List<UseEntry> list = blockMap.get(block); |
162 */ | 157 if (list == null) { |
163 private void analyzeBlock(AbstractBlock<?> block) { | 158 list = new ArrayList<>(); |
164 try (Indent indent = Debug.logAndIndent("Block: %s", block)) { | 159 blockMap.put(block, list); |
165 | 160 } |
166 InstructionValueConsumer loadConsumer = (instruction, value, mode, flags) -> { | 161 list.add(entry); |
167 if (isVariable(value)) { | 162 } |
168 Variable var = (Variable) value; | 163 |
169 | 164 /** |
170 if (!phiConstants.get(var.index)) { | 165 * Collects def-use information for a {@code block}. |
171 if (!defined.get(var.index)) { | 166 */ |
172 defined.set(var.index); | 167 private void analyzeBlock(AbstractBlock<?> block) { |
173 if (isConstantLoad(instruction)) { | 168 try (Indent indent = Debug.logAndIndent("Block: %s", block)) { |
174 Debug.log("constant load: %s", instruction); | 169 |
175 map.put(var, new DefUseTree(instruction, block)); | 170 InstructionValueConsumer loadConsumer = (instruction, value, mode, flags) -> { |
176 constantsTotal.increment(); | 171 if (isVariable(value)) { |
172 Variable var = (Variable) value; | |
173 | |
174 if (!phiConstants.get(var.index)) { | |
175 if (!defined.get(var.index)) { | |
176 defined.set(var.index); | |
177 if (isConstantLoad(instruction)) { | |
178 Debug.log("constant load: %s", instruction); | |
179 map.put(var, new DefUseTree(instruction, block)); | |
180 constantsTotal.increment(); | |
181 } | |
182 } else { | |
183 // Variable is redefined, this only happens for constant loads | |
184 // introduced by phi resolution -> ignore. | |
185 DefUseTree removed = map.remove(var); | |
186 if (removed != null) { | |
187 phiConstantsSkipped.increment(); | |
188 } | |
189 phiConstants.set(var.index); | |
190 Debug.log(3, "Removing phi variable: %s", var); | |
177 } | 191 } |
178 } else { | 192 } else { |
179 // Variable is redefined, this only happens for constant loads | 193 assert defined.get(var.index) : "phi but not defined? " + var; |
180 // introduced by phi resolution -> ignore. | |
181 DefUseTree removed = map.remove(var); | |
182 if (removed != null) { | |
183 phiConstantsSkipped.increment(); | |
184 } | |
185 phiConstants.set(var.index); | |
186 Debug.log(3, "Removing phi variable: %s", var); | |
187 } | |
188 } else { | |
189 assert defined.get(var.index) : "phi but not defined? " + var; | |
190 } | |
191 } | |
192 }; | |
193 | |
194 ValuePositionProcedure useProcedure = (instruction, position) -> { | |
195 Value value = position.get(instruction); | |
196 if (isVariable(value)) { | |
197 Variable var = (Variable) value; | |
198 if (!phiConstants.get(var.index)) { | |
199 DefUseTree tree = map.get(var); | |
200 if (tree != null) { | |
201 tree.addUsage(block, instruction, position); | |
202 Debug.log("usage of %s : %s", var, instruction); | |
203 } | 194 } |
204 } | 195 } |
205 } | 196 }; |
206 }; | 197 |
207 | 198 ValuePositionProcedure useProcedure = (instruction, position) -> { |
208 int opId = 0; | 199 Value value = position.get(instruction); |
209 for (LIRInstruction inst : lir.getLIRforBlock(block)) { | 200 if (isVariable(value)) { |
210 // set instruction id to the index in the lir instruction list | 201 Variable var = (Variable) value; |
211 inst.setId(opId++); | 202 if (!phiConstants.get(var.index)) { |
212 inst.visitEachOutput(loadConsumer); | 203 DefUseTree tree = map.get(var); |
213 inst.forEachInputPos(useProcedure); | 204 if (tree != null) { |
214 inst.forEachAlivePos(useProcedure); | 205 tree.addUsage(block, instruction, position); |
215 | 206 Debug.log("usage of %s : %s", var, instruction); |
216 } | 207 } |
217 } | 208 } |
218 } | 209 } |
219 | 210 }; |
220 /** | 211 |
221 * Creates the dominator tree and searches for an solution. | 212 int opId = 0; |
222 */ | 213 for (LIRInstruction inst : lir.getLIRforBlock(block)) { |
223 private void createConstantTree(DefUseTree tree) { | 214 // set instruction id to the index in the lir instruction list |
224 ConstantTree constTree = new ConstantTree(lir.getControlFlowGraph(), tree); | 215 inst.setId(opId++); |
225 constTree.set(Flags.SUBTREE, tree.getBlock()); | 216 inst.visitEachOutput(loadConsumer); |
226 tree.forEach(u -> constTree.set(Flags.USAGE, u.getBlock())); | 217 inst.forEachInputPos(useProcedure); |
227 | 218 inst.forEachAlivePos(useProcedure); |
228 if (constTree.get(Flags.USAGE, tree.getBlock())) { | 219 |
229 // usage in the definition block -> no optimization | 220 } |
230 usageAtDefinitionSkipped.increment(); | 221 } |
231 return; | 222 } |
232 } | 223 |
233 | 224 /** |
234 constTree.markBlocks(); | 225 * Creates the dominator tree and searches for an solution. |
235 | 226 */ |
236 NodeCost cost = ConstantTreeAnalyzer.analyze(constTree, tree.getBlock()); | 227 private void createConstantTree(DefUseTree tree) { |
237 int usageCount = cost.getUsages().size(); | 228 ConstantTree constTree = new ConstantTree(lir.getControlFlowGraph(), tree); |
238 assert usageCount == tree.usageCount() : "Usage count differs: " + usageCount + " vs. " + tree.usageCount(); | 229 constTree.set(Flags.SUBTREE, tree.getBlock()); |
239 | 230 tree.forEach(u -> constTree.set(Flags.USAGE, u.getBlock())); |
240 if (Debug.isLogEnabled()) { | 231 |
241 try (Indent i = Debug.logAndIndent("Variable: %s, Block: %s, prob.: %f", tree.getVariable(), tree.getBlock(), tree.getBlock().probability())) { | 232 if (constTree.get(Flags.USAGE, tree.getBlock())) { |
242 Debug.log("Usages result: %s", cost); | 233 // usage in the definition block -> no optimization |
243 } | 234 usageAtDefinitionSkipped.increment(); |
244 | 235 return; |
245 } | 236 } |
246 | 237 |
247 if (cost.getNumMaterializations() > 1 || cost.getBestCost() < tree.getBlock().probability()) { | 238 constTree.markBlocks(); |
248 try (Scope s = Debug.scope("CLOmodify", constTree); Indent i = Debug.logAndIndent("Replacing %s = %s", tree.getVariable(), tree.getConstant().toValueString())) { | 239 |
249 // mark original load for removal | 240 NodeCost cost = ConstantTreeAnalyzer.analyze(constTree, tree.getBlock()); |
250 deleteInstruction(tree); | 241 int usageCount = cost.getUsages().size(); |
251 constantsOptimized.increment(); | 242 assert usageCount == tree.usageCount() : "Usage count differs: " + usageCount + " vs. " + tree.usageCount(); |
252 | 243 |
253 // collect result | 244 if (Debug.isLogEnabled()) { |
254 createLoads(tree, constTree, tree.getBlock()); | 245 try (Indent i = Debug.logAndIndent("Variable: %s, Block: %s, prob.: %f", tree.getVariable(), tree.getBlock(), tree.getBlock().probability())) { |
255 | 246 Debug.log("Usages result: %s", cost); |
256 } catch (Throwable e) { | 247 } |
257 throw Debug.handle(e); | 248 |
258 } | 249 } |
259 } else { | 250 |
260 // no better solution found | 251 if (cost.getNumMaterializations() > 1 || cost.getBestCost() < tree.getBlock().probability()) { |
261 materializeAtDefinitionSkipped.increment(); | 252 try (Scope s = Debug.scope("CLOmodify", constTree); Indent i = Debug.logAndIndent("Replacing %s = %s", tree.getVariable(), tree.getConstant().toValueString())) { |
262 } | 253 // mark original load for removal |
263 Debug.dump(constTree, "ConstantTree for " + tree.getVariable()); | 254 deleteInstruction(tree); |
264 } | 255 constantsOptimized.increment(); |
265 | 256 |
266 private void createLoads(DefUseTree tree, ConstantTree constTree, AbstractBlock<?> startBlock) { | 257 // collect result |
267 Deque<AbstractBlock<?>> worklist = new ArrayDeque<>(); | 258 createLoads(tree, constTree, tree.getBlock()); |
268 worklist.add(startBlock); | 259 |
269 while (!worklist.isEmpty()) { | 260 } catch (Throwable e) { |
270 AbstractBlock<?> block = worklist.pollLast(); | 261 throw Debug.handle(e); |
271 if (constTree.get(Flags.CANDIDATE, block)) { | 262 } |
272 constTree.set(Flags.MATERIALIZE, block); | |
273 // create and insert load | |
274 insertLoad(tree.getConstant(), tree.getVariable().getLIRKind(), block, constTree.getCost(block).getUsages()); | |
275 } else { | 263 } else { |
276 for (AbstractBlock<?> dominated : block.getDominated()) { | 264 // no better solution found |
277 if (constTree.isMarked(dominated)) { | 265 materializeAtDefinitionSkipped.increment(); |
278 worklist.addLast(dominated); | 266 } |
267 Debug.dump(constTree, "ConstantTree for " + tree.getVariable()); | |
268 } | |
269 | |
270 private void createLoads(DefUseTree tree, ConstantTree constTree, AbstractBlock<?> startBlock) { | |
271 Deque<AbstractBlock<?>> worklist = new ArrayDeque<>(); | |
272 worklist.add(startBlock); | |
273 while (!worklist.isEmpty()) { | |
274 AbstractBlock<?> block = worklist.pollLast(); | |
275 if (constTree.get(Flags.CANDIDATE, block)) { | |
276 constTree.set(Flags.MATERIALIZE, block); | |
277 // create and insert load | |
278 insertLoad(tree.getConstant(), tree.getVariable().getLIRKind(), block, constTree.getCost(block).getUsages()); | |
279 } else { | |
280 for (AbstractBlock<?> dominated : block.getDominated()) { | |
281 if (constTree.isMarked(dominated)) { | |
282 worklist.addLast(dominated); | |
283 } | |
279 } | 284 } |
280 } | 285 } |
281 } | 286 } |
282 } | 287 } |
283 } | 288 |
284 | 289 private void insertLoad(JavaConstant constant, LIRKind kind, AbstractBlock<?> block, List<UseEntry> usages) { |
285 private void insertLoad(JavaConstant constant, LIRKind kind, AbstractBlock<?> block, List<UseEntry> usages) { | 290 assert usages != null && usages.size() > 0 : String.format("No usages %s %s %s", constant, block, usages); |
286 assert usages != null && usages.size() > 0 : String.format("No usages %s %s %s", constant, block, usages); | 291 // create variable |
287 // create variable | 292 Variable variable = lirGen.newVariable(kind); |
288 Variable variable = lirGen.newVariable(kind); | 293 // create move |
289 // create move | 294 LIRInstruction move = lir.getSpillMoveFactory().createMove(variable, constant); |
290 LIRInstruction move = lir.getSpillMoveFactory().createMove(variable, constant); | 295 // insert instruction |
291 // insert instruction | 296 getInsertionBuffer(block).append(1, move); |
292 getInsertionBuffer(block).append(1, move); | 297 Debug.log("new move (%s) and inserted in block %s", move, block); |
293 Debug.log("new move (%s) and inserted in block %s", move, block); | 298 // update usages |
294 // update usages | 299 for (UseEntry u : usages) { |
295 for (UseEntry u : usages) { | 300 u.getPosition().set(u.getInstruction(), variable); |
296 u.getPosition().set(u.getInstruction(), variable); | 301 Debug.log("patched instruction %s", u.getInstruction()); |
297 Debug.log("patched instruction %s", u.getInstruction()); | 302 } |
298 } | 303 } |
299 } | 304 |
300 | 305 /** |
301 /** | 306 * Inserts the constant loads created in {@link #createConstantTree} and deletes the |
302 * Inserts the constant loads created in {@link #createConstantTree} and deletes the original | 307 * original definition. |
303 * definition. | 308 */ |
304 */ | 309 private void rewriteBlock(AbstractBlock<?> block) { |
305 private void rewriteBlock(AbstractBlock<?> block) { | 310 // insert moves |
306 // insert moves | 311 LIRInsertionBuffer buffer = insertionBuffers.get(block); |
307 LIRInsertionBuffer buffer = insertionBuffers.get(block); | 312 if (buffer != null) { |
308 if (buffer != null) { | 313 assert buffer.initialized() : "not initialized?"; |
309 assert buffer.initialized() : "not initialized?"; | 314 buffer.finish(); |
310 buffer.finish(); | 315 } |
311 } | 316 |
312 | 317 // delete instructions |
313 // delete instructions | |
314 List<LIRInstruction> instructions = lir.getLIRforBlock(block); | |
315 boolean hasDead = false; | |
316 for (LIRInstruction inst : instructions) { | |
317 if (inst == null) { | |
318 hasDead = true; | |
319 } else { | |
320 inst.setId(-1); | |
321 } | |
322 } | |
323 if (hasDead) { | |
324 // Remove null values from the list. | |
325 instructions.removeAll(Collections.singleton(null)); | |
326 } | |
327 } | |
328 | |
329 private void deleteInstruction(DefUseTree tree) { | |
330 AbstractBlock<?> block = tree.getBlock(); | |
331 LIRInstruction instruction = tree.getInstruction(); | |
332 Debug.log("deleting instruction %s from block %s", instruction, block); | |
333 lir.getLIRforBlock(block).set(instruction.id(), null); | |
334 } | |
335 | |
336 private LIRInsertionBuffer getInsertionBuffer(AbstractBlock<?> block) { | |
337 LIRInsertionBuffer insertionBuffer = insertionBuffers.get(block); | |
338 if (insertionBuffer == null) { | |
339 insertionBuffer = new LIRInsertionBuffer(); | |
340 insertionBuffers.put(block, insertionBuffer); | |
341 assert !insertionBuffer.initialized() : "already initialized?"; | |
342 List<LIRInstruction> instructions = lir.getLIRforBlock(block); | 318 List<LIRInstruction> instructions = lir.getLIRforBlock(block); |
343 insertionBuffer.init(instructions); | 319 boolean hasDead = false; |
344 } | 320 for (LIRInstruction inst : instructions) { |
345 return insertionBuffer; | 321 if (inst == null) { |
322 hasDead = true; | |
323 } else { | |
324 inst.setId(-1); | |
325 } | |
326 } | |
327 if (hasDead) { | |
328 // Remove null values from the list. | |
329 instructions.removeAll(Collections.singleton(null)); | |
330 } | |
331 } | |
332 | |
333 private void deleteInstruction(DefUseTree tree) { | |
334 AbstractBlock<?> block = tree.getBlock(); | |
335 LIRInstruction instruction = tree.getInstruction(); | |
336 Debug.log("deleting instruction %s from block %s", instruction, block); | |
337 lir.getLIRforBlock(block).set(instruction.id(), null); | |
338 } | |
339 | |
340 private LIRInsertionBuffer getInsertionBuffer(AbstractBlock<?> block) { | |
341 LIRInsertionBuffer insertionBuffer = insertionBuffers.get(block); | |
342 if (insertionBuffer == null) { | |
343 insertionBuffer = new LIRInsertionBuffer(); | |
344 insertionBuffers.put(block, insertionBuffer); | |
345 assert !insertionBuffer.initialized() : "already initialized?"; | |
346 List<LIRInstruction> instructions = lir.getLIRforBlock(block); | |
347 insertionBuffer.init(instructions); | |
348 } | |
349 return insertionBuffer; | |
350 } | |
346 } | 351 } |
347 } | 352 } |