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