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 }