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