001 /*
002 * This file is part of the Jikes RVM project (http://jikesrvm.org).
003 *
004 * This file is licensed to You under the Eclipse Public License (EPL);
005 * You may not use this file except in compliance with the License. You
006 * may obtain a copy of the License at
007 *
008 * http://www.opensource.org/licenses/eclipse-1.0.php
009 *
010 * See the COPYRIGHT.txt file distributed with this work for information
011 * regarding copyright ownership.
012 */
013 package org.jikesrvm.compilers.opt.ssa;
014
015 import static org.jikesrvm.compilers.opt.ir.Operators.BYTE_ALOAD_opcode;
016 import static org.jikesrvm.compilers.opt.ir.Operators.BYTE_ASTORE_opcode;
017 import static org.jikesrvm.compilers.opt.ir.Operators.DOUBLE_ALOAD_opcode;
018 import static org.jikesrvm.compilers.opt.ir.Operators.DOUBLE_ASTORE_opcode;
019 import static org.jikesrvm.compilers.opt.ir.Operators.FLOAT_ALOAD_opcode;
020 import static org.jikesrvm.compilers.opt.ir.Operators.FLOAT_ASTORE_opcode;
021 import static org.jikesrvm.compilers.opt.ir.Operators.GETFIELD_opcode;
022 import static org.jikesrvm.compilers.opt.ir.Operators.GETSTATIC_opcode;
023 import static org.jikesrvm.compilers.opt.ir.Operators.INT_ALOAD_opcode;
024 import static org.jikesrvm.compilers.opt.ir.Operators.INT_ASTORE_opcode;
025 import static org.jikesrvm.compilers.opt.ir.Operators.LONG_ALOAD_opcode;
026 import static org.jikesrvm.compilers.opt.ir.Operators.LONG_ASTORE_opcode;
027 import static org.jikesrvm.compilers.opt.ir.Operators.PUTFIELD_opcode;
028 import static org.jikesrvm.compilers.opt.ir.Operators.PUTSTATIC_opcode;
029 import static org.jikesrvm.compilers.opt.ir.Operators.REF_ALOAD_opcode;
030 import static org.jikesrvm.compilers.opt.ir.Operators.REF_ASTORE_opcode;
031 import static org.jikesrvm.compilers.opt.ir.Operators.SHORT_ALOAD_opcode;
032 import static org.jikesrvm.compilers.opt.ir.Operators.SHORT_ASTORE_opcode;
033 import static org.jikesrvm.compilers.opt.ir.Operators.UBYTE_ALOAD_opcode;
034 import static org.jikesrvm.compilers.opt.ir.Operators.USHORT_ALOAD_opcode;
035
036 import java.lang.reflect.Constructor;
037 import java.util.Enumeration;
038 import java.util.HashMap;
039 import java.util.HashSet;
040 import java.util.Iterator;
041
042 import org.jikesrvm.ArchitectureSpecificOpt.RegisterPool;
043 import org.jikesrvm.classloader.RVMField;
044 import org.jikesrvm.classloader.FieldReference;
045 import org.jikesrvm.classloader.TypeReference;
046 import org.jikesrvm.compilers.opt.OptOptions;
047 import org.jikesrvm.compilers.opt.OptimizingCompilerException;
048 import org.jikesrvm.compilers.opt.dfsolver.DF_Solution;
049 import org.jikesrvm.compilers.opt.driver.CompilerPhase;
050 import org.jikesrvm.compilers.opt.driver.OptimizationPlanAtomicElement;
051 import org.jikesrvm.compilers.opt.driver.OptimizationPlanCompositeElement;
052 import org.jikesrvm.compilers.opt.driver.OptimizationPlanElement;
053 import org.jikesrvm.compilers.opt.ir.ALoad;
054 import org.jikesrvm.compilers.opt.ir.AStore;
055 import org.jikesrvm.compilers.opt.ir.BasicBlock;
056 import org.jikesrvm.compilers.opt.ir.GetField;
057 import org.jikesrvm.compilers.opt.ir.GetStatic;
058 import org.jikesrvm.compilers.opt.ir.IR;
059 import org.jikesrvm.compilers.opt.ir.IRTools;
060 import org.jikesrvm.compilers.opt.ir.Instruction;
061 import org.jikesrvm.compilers.opt.ir.InstructionEnumeration;
062 import org.jikesrvm.compilers.opt.ir.Move;
063 import org.jikesrvm.compilers.opt.ir.PutField;
064 import org.jikesrvm.compilers.opt.ir.PutStatic;
065 import org.jikesrvm.compilers.opt.ir.Register;
066 import org.jikesrvm.compilers.opt.ir.ResultCarrier;
067 import org.jikesrvm.compilers.opt.ir.operand.HeapOperand;
068 import org.jikesrvm.compilers.opt.ir.operand.Operand;
069 import org.jikesrvm.compilers.opt.ir.operand.RegisterOperand;
070 import org.jikesrvm.compilers.opt.ssa.IndexPropagation.ArrayCell;
071 import org.jikesrvm.compilers.opt.ssa.IndexPropagation.ObjectCell;
072
073 /**
074 * This class implements the redundant load elimination by
075 * Fink, Knobe && Sarkar. See SAS 2000 paper for details.
076 */
077 public final class LoadElimination extends OptimizationPlanCompositeElement {
078
079 /**
080 * @param round which round of load elimination is this?
081 */
082 public LoadElimination(int round) {
083 super("Load Elimination",
084 new OptimizationPlanElement[]{new OptimizationPlanAtomicElement(new GVNPreparation(round)),
085 new OptimizationPlanAtomicElement(new EnterSSA()),
086 new OptimizationPlanAtomicElement(new GlobalValueNumber()),
087 new OptimizationPlanAtomicElement(new LoadEliminationPreparation(round)),
088 new OptimizationPlanAtomicElement(new EnterSSA()),
089 new OptimizationPlanAtomicElement(new IndexPropagation()),
090 new OptimizationPlanAtomicElement(new LoadEliminator())});
091 this.round = round;
092 }
093
094 static final boolean DEBUG = false;
095
096 public boolean shouldPerform(OptOptions options) {
097 return options.SSA_LOAD_ELIMINATION;
098 }
099
100 public String getName() {
101 return "Array SSA Load Elimination, round " + round;
102 }
103
104 /**
105 * which round of load elimination is this?
106 */
107 private final int round;
108
109 static final class LoadEliminator extends CompilerPhase {
110 public String getName() {
111 return "Load Eliminator";
112 }
113
114 /**
115 * Return this instance of this phase. This phase contains no
116 * per-compilation instance fields.
117 * @param ir not used
118 * @return this
119 */
120 public CompilerPhase newExecution(IR ir) {
121 return this;
122 }
123
124 /**
125 * main driver for redundant load elimination
126 * Preconditions: Array SSA form and Global Value Numbers computed
127 * @param ir the governing IR
128 */
129 public void perform(IR ir) {
130
131 if (ir.desiredSSAOptions.getAbort()) return;
132
133 boolean didSomething = eliminateLoads(ir, ir.HIRInfo.indexPropagationSolution);
134 // Note that SSA is no longer valid!!!
135 // This will force construction of SSA next time we call EnterSSA
136 ir.actualSSAOptions.setScalarValid(false);
137 ir.actualSSAOptions.setHeapValid(false);
138 ir.HIRInfo.loadEliminationDidSomething = didSomething;
139
140 // clear the following field to avoid excess memory retention
141 ir.HIRInfo.indexPropagationSolution = null;
142 }
143 }
144
145 /**
146 * Eliminate redundant loads with respect to prior defs and prior
147 * uses.
148 *
149 * @return true if any load is eliminated.
150 */
151 static boolean eliminateLoads(IR ir, DF_Solution available) {
152 // maintain a mapping from value number to temporary register
153 HashMap<UseRecord, Register> registers = new HashMap<UseRecord, Register>();
154 UseRecordSet UseRepSet = replaceLoads(ir, available, registers);
155 replaceDefs(ir, UseRepSet, registers);
156
157 return (UseRepSet.size() > 0);
158 }
159
160 /**
161 * Walk over each instruction. If its a USE (load) of a heap
162 * variable and the value is available, then replace the load
163 * with a move from a register.
164 *
165 * POSTCONDITION: sets up the mapping 'registers' from value number
166 * to temporary register
167 * @param ir the IR
168 * @param available information on which values are available
169 * @param registers a place to store information about temp registers
170 */
171 static UseRecordSet replaceLoads(IR ir, DF_Solution available, HashMap<UseRecord, Register> registers) {
172 UseRecordSet result = new UseRecordSet();
173 SSADictionary ssa = ir.HIRInfo.dictionary;
174 GlobalValueNumberState valueNumbers = ir.HIRInfo.valueNumbers;
175 for (Enumeration<Instruction> e = ir.forwardInstrEnumerator(); e.hasMoreElements();) {
176 Instruction s = e.nextElement();
177 if (!GetField.conforms(s) && !GetStatic.conforms(s) && !ALoad.conforms(s)) {
178 continue;
179 }
180 // this instruction is a USE of heap variable H.
181 // get the lattice cell that holds the available indices
182 // for this heap variable
183 HeapOperand<?>[] H = ssa.getHeapUses(s);
184 if (H == null) {
185 // this case can happen due to certain magics that insert
186 // INT_LOAD instructions in HIR
187 // TODO: clean up HIR representation of these magics
188 continue;
189 }
190 if (H.length != 1) {
191 throw new OptimizingCompilerException("LoadElimination: load with wrong number of heap uses");
192 }
193 if (GetField.conforms(s) || GetStatic.conforms(s)) {
194 int valueNumber = -1;
195 if (GetField.conforms(s)) {
196 Object address = GetField.getRef(s);
197 valueNumber = valueNumbers.getValueNumber(address);
198 } else {
199 // for getStatic, always use the value number 0
200 valueNumber = 0;
201 }
202 ObjectCell cell = (ObjectCell) available.lookup(H[0].getHeapVariable());
203 if (cell == null) {
204 continue; // nothing available
205 }
206
207 // .. if H{valueNumber} is available ...
208 if (cell.contains(valueNumber)) {
209 result.add(H[0].getHeapVariable(), valueNumber);
210 TypeReference type = ResultCarrier.getResult(s).getType();
211 Register r = findOrCreateRegister(H[0].getHeapType(), valueNumber, registers, ir.regpool, type);
212 if (DEBUG) {
213 System.out.println("ELIMINATING LOAD " + s);
214 }
215 replaceLoadWithMove(r, s);
216 }
217 } else { // ALoad.conforms(s)
218 Object array = ALoad.getArray(s);
219 Object index = ALoad.getIndex(s);
220 ArrayCell cell = (ArrayCell) available.lookup(H[0].getHeapVariable());
221 if (cell == null) {
222 continue; // nothing available
223 }
224 int v1 = valueNumbers.getValueNumber(array);
225 int v2 = valueNumbers.getValueNumber(index);
226 // .. if H{<v1,v2>} is available ...
227 if (cell.contains(v1, v2)) {
228 result.add(H[0].getHeapVariable(), v1, v2);
229 TypeReference type = ALoad.getResult(s).getType();
230 Register r =
231 findOrCreateRegister(H[0].getHeapVariable().getHeapType(), v1, v2, registers, ir.regpool, type);
232 if (DEBUG) {
233 System.out.println("ELIMINATING LOAD " + s);
234 }
235 replaceLoadWithMove(r, s);
236 }
237 }
238 }
239 return result;
240 }
241
242 /**
243 * Replace a Load instruction s with a load from a scalar register r
244 * TODO: factor this functionality out elsewhere
245 */
246 static void replaceLoadWithMove(Register r, Instruction load) {
247 RegisterOperand dest = ResultCarrier.getResult(load);
248 RegisterOperand rop = new RegisterOperand(r, dest.getType());
249 load.replace(Move.create(IRTools.getMoveOp(dest.getType()), dest, rop));
250 }
251
252 /**
253 * Perform scalar replacement actions for a Def of a heap variable.
254 * NOTE: Even loads can def a heap variable.
255 *
256 * @param UseRepSet stores the uses(loads) that have been eliminated
257 * @param registers mapping from valueNumber -> temporary register
258 */
259 static void replaceDefs(IR ir, UseRecordSet UseRepSet, HashMap<UseRecord, Register> registers) {
260 SSADictionary ssa = ir.HIRInfo.dictionary;
261 for (Enumeration<Instruction> e = ir.forwardInstrEnumerator(); e.hasMoreElements();) {
262 Instruction s = e.nextElement();
263 if (!GetField.conforms(s) &&
264 !GetStatic.conforms(s) &&
265 !PutField.conforms(s) &&
266 !PutStatic.conforms(s) &&
267 !ALoad.conforms(s) &&
268 !AStore.conforms(s)) {
269 continue;
270 }
271 if (!ssa.defsHeapVariable(s)) {
272 continue;
273 }
274 // this instruction is a DEF of heap variable H.
275 // Check if UseRepSet needs the scalar assigned by this def
276 HeapOperand<?>[] H = ssa.getHeapDefs(s);
277 if (H.length != 1) {
278 throw new OptimizingCompilerException("LoadElimination: encountered a store with more than one def? " +
279 s);
280 }
281 int valueNumber = -1;
282 Object index = null;
283 if (AStore.conforms(s)) {
284 Object address = AStore.getArray(s);
285 index = AStore.getIndex(s);
286 valueNumber = ir.HIRInfo.valueNumbers.getValueNumber(address);
287 } else if (GetField.conforms(s)) {
288 Object address = GetField.getRef(s);
289 valueNumber = ir.HIRInfo.valueNumbers.getValueNumber(address);
290 } else if (PutField.conforms(s)) {
291 Object address = PutField.getRef(s);
292 valueNumber = ir.HIRInfo.valueNumbers.getValueNumber(address);
293 } else if (GetStatic.conforms(s)) {
294 valueNumber = 0;
295 } else if (PutStatic.conforms(s)) {
296 valueNumber = 0;
297 } else if (ALoad.conforms(s)) {
298 Object address = ALoad.getArray(s);
299 valueNumber = ir.HIRInfo.valueNumbers.getValueNumber(address);
300 index = ALoad.getIndex(s);
301 }
302 if (index == null) {
303 // Load/Store
304 if (UseRepSet.containsMatchingUse(H[0].getHeapVariable(), valueNumber)) {
305 Operand value = null;
306 if (PutField.conforms(s)) {
307 value = PutField.getValue(s);
308 } else if (PutStatic.conforms(s)) {
309 value = PutStatic.getValue(s);
310 } else if (GetField.conforms(s) || GetStatic.conforms(s)) {
311 value = ResultCarrier.getResult(s);
312 }
313 TypeReference type = value.getType();
314 Register r = findOrCreateRegister(H[0].getHeapType(), valueNumber, registers, ir.regpool, type);
315 appendMove(r, value, s);
316 }
317 } else {
318 // ALoad / AStore
319 int v1 = valueNumber;
320 int v2 = ir.HIRInfo.valueNumbers.getValueNumber(index);
321 if (UseRepSet.containsMatchingUse(H[0].getHeapVariable(), v1, v2)) {
322 Operand value = null;
323 if (AStore.conforms(s)) {
324 value = AStore.getValue(s);
325 } else if (ALoad.conforms(s)) {
326 value = ALoad.getResult(s);
327 }
328 TypeReference type = value.getType();
329 Register r = findOrCreateRegister(H[0].getHeapType(), v1, v2, registers, ir.regpool, type);
330 appendMove(r, value, s);
331 }
332 }
333 }
334 }
335
336 /**
337 * Append an instruction after a store instruction that caches
338 * value in register r.
339 */
340 static void appendMove(Register r, Operand src, Instruction store) {
341 TypeReference type = src.getType();
342 RegisterOperand rop = new RegisterOperand(r, type);
343 store.insertAfter(Move.create(IRTools.getMoveOp(type), rop, src.copy()));
344 }
345
346 /**
347 * Given a value number, return the temporary register allocated
348 * for that value number. Create one if necessary.
349 *
350 * @param heapType a TypeReference or RVMField identifying the array SSA
351 * heap type
352 * @param valueNumber
353 * @param registers a mapping from value number to temporary register
354 * @param pool register pool to allocate new temporaries from
355 * @param type the type to store in the new register
356 */
357 static Register findOrCreateRegister(Object heapType, int valueNumber, HashMap<UseRecord, Register> registers,
358 RegisterPool pool, TypeReference type) {
359 UseRecord key = new UseRecord(heapType, valueNumber);
360 Register result = registers.get(key);
361 if (result == null) {
362 // create a new temp and insert it in the mapping
363 result = pool.makeTemp(type).getRegister();
364 registers.put(key, result);
365 }
366 return result;
367 }
368
369 /**
370 * Given a pair of value numbers, return the temporary register
371 * allocated for that pair. Create one if necessary.
372 *
373 * @param heapType a TypeReference identifying the array SSA
374 * heap type
375 * @param v1 first value number
376 * @param v2 second value number
377 * @param registers a mapping from value number to temporary register
378 * @param pool register pool to allocate new temporaries from
379 * @param type the type to store in the new register
380 */
381 static Register findOrCreateRegister(Object heapType, int v1, int v2, HashMap<UseRecord, Register> registers,
382 RegisterPool pool, TypeReference type) {
383 UseRecord key = new UseRecord(heapType, v1, v2);
384 Register result = registers.get(key);
385 if (result == null) {
386 // create a new temp and insert it in the mapping
387 result = pool.makeTemp(type).getRegister();
388 registers.put(key, result);
389 }
390 return result;
391 }
392
393 // A UseRecord represents a load that will be eliminated
394 static class UseRecord {
395 final Object type; // may be either a TypeReference or a RVMField
396 final int v1; // first value number (object pointer)
397 final int v2; // second value number (array index)
398 static final int NONE = -2;
399
400 UseRecord(Object type, int valueNumber) {
401 this.type = type;
402 this.v1 = valueNumber;
403 this.v2 = NONE;
404 }
405
406 UseRecord(Object type, int v1, int v2) {
407 this.type = type;
408 this.v1 = v1;
409 this.v2 = v2;
410 }
411
412 public boolean equals(Object o) {
413 if (o instanceof UseRecord) {
414 UseRecord u = (UseRecord) o;
415 return ((u.type.equals(type)) && (u.v1 == v1) && (u.v2 == v2));
416 }
417 return false;
418 }
419
420 public int hashCode() {
421 return type.hashCode() + v1 + v2;
422 }
423 }
424
425 static final class UseRecordSet {
426 final HashSet<UseRecord> set = new HashSet<UseRecord>(10);
427
428 // Does this set contain a use that has the same type as H and
429 // the given value number?
430 boolean containsMatchingUse(HeapVariable<?> H, int valueNumber) {
431 Object type = H.getHeapType();
432 UseRecord u = new UseRecord(type, valueNumber);
433 return (set.contains(u));
434 }
435
436 // Does this set contain a use that has the same type as H and
437 // the given value number pair <v1,v2>?
438 boolean containsMatchingUse(HeapVariable<?> H, int v1, int v2) {
439 Object type = H.getHeapType();
440 UseRecord u = new UseRecord(type, v1, v2);
441 return (set.contains(u));
442 }
443
444 // add a USE to the set
445 void add(HeapVariable<?> H, int valueNumber) {
446 UseRecord u = new UseRecord(H.getHeapType(), valueNumber);
447 set.add(u);
448 }
449
450 void add(HeapVariable<?> H, int v1, int v2) {
451 UseRecord u = new UseRecord(H.getHeapType(), v1, v2);
452 set.add(u);
453 }
454
455 int size() { return set.size(); }
456 }
457
458 /**
459 * @param map a mapping from key to HashSet
460 * @param key a key into the map
461 * @return the set map(key). create one if none exists.
462 */
463 private static <T> HashSet<T> findOrCreateIndexSet(HashMap<Object, HashSet<T>> map, Object key) {
464 HashSet<T> result = map.get(key);
465 if (result == null) {
466 result = new HashSet<T>(5);
467 map.put(key, result);
468 }
469 return result;
470 }
471
472 /**
473 * Do a quick pass over the IR, and return types that are candidates
474 * for redundant load elimination.
475 * Algorithm: return those types T where
476 * 1) there's a load L(i) of type T
477 * 2) there's another load or store M(j) of type T, M!=L and V(i) == V(j)
478 *
479 * The result contains objects of type RVMField and TypeReference, whose
480 * narrowest common ancestor is Object.
481 */
482 @SuppressWarnings("unchecked")
483 public static HashSet<Object> getCandidates(IR ir) {
484 GlobalValueNumberState valueNumbers = ir.HIRInfo.valueNumbers;
485 // which types have we seen loads for?
486 HashSet<Object> seenLoad = new HashSet<Object>(10);
487 // which static fields have we seen stores for?
488 HashSet<RVMField> seenStore = new HashSet<RVMField>(10);
489 HashSet<Object> resultSet = new HashSet<Object>(10);
490 HashSet<FieldReference> forbidden = new HashSet<FieldReference>(10);
491 // for each type T, indices(T) gives the set of value number (pairs)
492 // that identify the indices seen in memory accesses to type T.
493 HashMap indices = new HashMap(10);
494
495 for (Enumeration be = ir.getBasicBlocks(); be.hasMoreElements();) {
496 BasicBlock bb = (BasicBlock) be.nextElement();
497 if (!ir.options.FREQ_FOCUS_EFFORT || !bb.getInfrequent()) {
498 for (InstructionEnumeration e = bb.forwardInstrEnumerator(); e.hasMoreElements();) {
499 Instruction s = e.next();
500 switch (s.operator().opcode) {
501 case GETFIELD_opcode: {
502 Operand ref = GetField.getRef(s);
503 FieldReference fr = GetField.getLocation(s).getFieldRef();
504 RVMField f = fr.peekResolvedField();
505 if (f == null) {
506 forbidden.add(fr);
507 } else {
508 HashSet<Integer> numbers = findOrCreateIndexSet(indices, f);
509 int v = valueNumbers.getValueNumber(ref);
510 Integer V = v;
511 if (numbers.contains(V)) {
512 resultSet.add(f);
513 } else {
514 numbers.add(V);
515 }
516 seenLoad.add(f);
517 }
518 }
519 break;
520 case PUTFIELD_opcode: {
521 Operand ref = PutField.getRef(s);
522 FieldReference fr = PutField.getLocation(s).getFieldRef();
523 RVMField f = fr.peekResolvedField();
524 if (f == null) {
525 forbidden.add(fr);
526 } else {
527 HashSet<Integer> numbers = findOrCreateIndexSet(indices, f);
528 int v = valueNumbers.getValueNumber(ref);
529 Integer V = v;
530 if (numbers.contains(V)) {
531 if (seenLoad.contains(f)) {
532 resultSet.add(f);
533 }
534 } else {
535 numbers.add(V);
536 }
537 }
538 }
539 break;
540 case GETSTATIC_opcode: {
541 FieldReference fr = GetStatic.getLocation(s).getFieldRef();
542 RVMField f = fr.peekResolvedField();
543 if (f == null) {
544 forbidden.add(fr);
545 } else {
546 if (seenLoad.contains(f) || seenStore.contains(f)) {
547 resultSet.add(f);
548 }
549 seenLoad.add(f);
550 }
551 }
552 break;
553 case PUTSTATIC_opcode: {
554 FieldReference fr = PutStatic.getLocation(s).getFieldRef();
555 RVMField f = fr.peekResolvedField();
556 if (f == null) {
557 forbidden.add(fr);
558 } else {
559 if (seenLoad.contains(f)) {
560 resultSet.add(f);
561 }
562 seenStore.add(f);
563 }
564 }
565 break;
566 case INT_ALOAD_opcode:
567 case LONG_ALOAD_opcode:
568 case FLOAT_ALOAD_opcode:
569 case DOUBLE_ALOAD_opcode:
570 case REF_ALOAD_opcode:
571 case BYTE_ALOAD_opcode:
572 case UBYTE_ALOAD_opcode:
573 case USHORT_ALOAD_opcode:
574 case SHORT_ALOAD_opcode: {
575 Operand ref = ALoad.getArray(s);
576 TypeReference type = ref.getType();
577 if (type.isArrayType()) {
578 if (!type.getArrayElementType().isPrimitiveType()) {
579 type = TypeReference.JavaLangObjectArray;
580 }
581 }
582 Operand index = ALoad.getIndex(s);
583
584 HashSet<ValueNumberPair> numbers = findOrCreateIndexSet(indices, type);
585 int v1 = valueNumbers.getValueNumber(ref);
586 int v2 = valueNumbers.getValueNumber(index);
587 ValueNumberPair V = new ValueNumberPair(v1, v2);
588 if (numbers.contains(V)) {
589 resultSet.add(type);
590 } else {
591 numbers.add(V);
592 }
593 seenLoad.add(type);
594 }
595
596 break;
597
598 case INT_ASTORE_opcode:
599 case LONG_ASTORE_opcode:
600 case FLOAT_ASTORE_opcode:
601 case DOUBLE_ASTORE_opcode:
602 case REF_ASTORE_opcode:
603 case BYTE_ASTORE_opcode:
604 case SHORT_ASTORE_opcode:
605
606 {
607 Operand ref = AStore.getArray(s);
608 TypeReference type = ref.getType();
609 if (type.isArrayType()) {
610 if (!type.getArrayElementType().isPrimitiveType()) {
611 type = TypeReference.JavaLangObjectArray;
612 }
613 }
614 Operand index = AStore.getIndex(s);
615
616 HashSet<ValueNumberPair> numbers = findOrCreateIndexSet(indices, type);
617 int v1 = valueNumbers.getValueNumber(ref);
618 int v2 = valueNumbers.getValueNumber(index);
619 ValueNumberPair V = new ValueNumberPair(v1, v2);
620
621 if (numbers.contains(V)) {
622 if (seenLoad.contains(type)) {
623 resultSet.add(type);
624 }
625 } else {
626 numbers.add(V);
627 }
628 }
629 break;
630
631 default:
632 break;
633 }
634 }
635 }
636 }
637
638 // If we have found an unresolved field reference, then conservatively
639 // remove all fields that it might refer to from the resultSet.
640 for (final FieldReference fieldReference : forbidden) {
641 for (Iterator i2 = resultSet.iterator(); i2.hasNext();) {
642 Object it = i2.next();
643 if (it instanceof RVMField) {
644 final RVMField field = (RVMField) it;
645 if (!fieldReference.definitelyDifferent(field.getMemberRef().asFieldReference())) {
646 i2.remove();
647 }
648 }
649 }
650 }
651
652 return resultSet;
653 }
654
655 /**
656 * This class sets up the IR state prior to entering SSA for load
657 * elimination
658 */
659 public static class LoadEliminationPreparation extends CompilerPhase {
660 /**
661 * Cosntructor
662 */
663 public LoadEliminationPreparation(int round) {
664 super(new Object[]{round});
665 this.round = round;
666 }
667
668 /**
669 * Constructor for this compiler phase
670 */
671 private static final Constructor<CompilerPhase> constructor =
672 getCompilerPhaseConstructor(LoadEliminationPreparation.class, new Class[]{Integer.TYPE});
673
674 /**
675 * Get a constructor object for this compiler phase
676 * @return compiler phase constructor
677 */
678 public Constructor<CompilerPhase> getClassConstructor() {
679 return constructor;
680 }
681
682 public final boolean shouldPerform(OptOptions options) {
683 return options.SSA_LOAD_ELIMINATION;
684 }
685
686 public final String getName() {
687 return "Load Elimination Preparation";
688 }
689
690 private final int round;
691
692 public final void perform(IR ir) {
693 // register in the IR the SSA properties we need for load
694 // elimination
695 ir.desiredSSAOptions = new SSAOptions();
696 ir.desiredSSAOptions.setScalarsOnly(false);
697 ir.desiredSSAOptions.setBackwards(false);
698 ir.desiredSSAOptions.setInsertUsePhis(true);
699 ir.desiredSSAOptions.setHeapTypes(LoadElimination.getCandidates(ir));
700 ir.desiredSSAOptions.setAbort((round > ir.options.SSA_LOAD_ELIMINATION_ROUNDS) ||
701 (!ir.HIRInfo.loadEliminationDidSomething));
702 }
703 }
704
705 /**
706 * This class sets up the IR state prior to entering SSA for GVN.
707 */
708 public static class GVNPreparation extends CompilerPhase {
709
710 public final boolean shouldPerform(OptOptions options) {
711 return options.SSA_LOAD_ELIMINATION;
712 }
713
714 public final String getName() {
715 return "GVN Preparation";
716 }
717
718 private final int round;
719
720 /**
721 * Constructor
722 */
723 public GVNPreparation(int round) {
724 super(new Object[]{round});
725 this.round = round;
726 }
727
728 /**
729 * Constructor for this compiler phase
730 */
731 private static final Constructor<CompilerPhase> constructor =
732 getCompilerPhaseConstructor(GVNPreparation.class, new Class[]{Integer.TYPE});
733
734 /**
735 * Get a constructor object for this compiler phase
736 * @return compiler phase constructor
737 */
738 public Constructor<CompilerPhase> getClassConstructor() {
739 return constructor;
740 }
741
742 public final void perform(IR ir) {
743 // register in the IR the SSA properties we need for load
744 // elimination
745 ir.desiredSSAOptions = new SSAOptions();
746 ir.desiredSSAOptions.setScalarsOnly(true);
747 ir.desiredSSAOptions.setBackwards(false);
748 ir.desiredSSAOptions.setInsertUsePhis(false);
749 ir.desiredSSAOptions.setAbort((round > ir.options.SSA_LOAD_ELIMINATION_ROUNDS) ||
750 (!ir.HIRInfo.loadEliminationDidSomething));
751 }
752 }
753 }