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; 014 015 import java.lang.reflect.Constructor; 016 import java.util.ArrayList; 017 import java.util.Enumeration; 018 019 import org.jikesrvm.VM; 020 import org.jikesrvm.compilers.opt.driver.CompilerPhase; 021 import org.jikesrvm.compilers.opt.ir.Binary; 022 import org.jikesrvm.compilers.opt.ir.BoundsCheck; 023 import org.jikesrvm.compilers.opt.ir.Call; 024 import org.jikesrvm.compilers.opt.ir.GetField; 025 import org.jikesrvm.compilers.opt.ir.GetStatic; 026 import org.jikesrvm.compilers.opt.ir.GuardResultCarrier; 027 import org.jikesrvm.compilers.opt.ir.GuardedBinary; 028 import org.jikesrvm.compilers.opt.ir.GuardedUnary; 029 import org.jikesrvm.compilers.opt.ir.InstanceOf; 030 import org.jikesrvm.compilers.opt.ir.LocationCarrier; 031 import org.jikesrvm.compilers.opt.ir.Move; 032 import org.jikesrvm.compilers.opt.ir.NullCheck; 033 import org.jikesrvm.compilers.opt.ir.BasicBlock; 034 import org.jikesrvm.compilers.opt.ir.IR; 035 import org.jikesrvm.compilers.opt.ir.IRTools; 036 import org.jikesrvm.compilers.opt.ir.Instruction; 037 import org.jikesrvm.compilers.opt.ir.InstructionFormat; 038 import org.jikesrvm.compilers.opt.ir.Operator; 039 import static org.jikesrvm.compilers.opt.ir.Operators.BOUNDS_CHECK_opcode; 040 import static org.jikesrvm.compilers.opt.ir.Operators.GUARD_MOVE; 041 import static org.jikesrvm.compilers.opt.ir.Operators.INT_ZERO_CHECK_opcode; 042 import static org.jikesrvm.compilers.opt.ir.Operators.LONG_ZERO_CHECK_opcode; 043 import static org.jikesrvm.compilers.opt.ir.Operators.MONITORENTER_opcode; 044 import static org.jikesrvm.compilers.opt.ir.Operators.MONITOREXIT_opcode; 045 import static org.jikesrvm.compilers.opt.ir.Operators.NULL_CHECK_opcode; 046 import static org.jikesrvm.compilers.opt.ir.Operators.READ_CEILING_opcode; 047 import static org.jikesrvm.compilers.opt.ir.Operators.REF_MOVE; 048 import static org.jikesrvm.compilers.opt.ir.Operators.TRAP_IF_opcode; 049 import static org.jikesrvm.compilers.opt.ir.Operators.WRITE_FLOOR_opcode; 050 import org.jikesrvm.compilers.opt.ir.Register; 051 import org.jikesrvm.compilers.opt.ir.PutField; 052 import org.jikesrvm.compilers.opt.ir.PutStatic; 053 import org.jikesrvm.compilers.opt.ir.ResultCarrier; 054 import org.jikesrvm.compilers.opt.ir.TrapIf; 055 import org.jikesrvm.compilers.opt.ir.TypeCheck; 056 import org.jikesrvm.compilers.opt.ir.Unary; 057 import org.jikesrvm.compilers.opt.ir.ZeroCheck; 058 import org.jikesrvm.compilers.opt.ir.operand.IntConstantOperand; 059 import org.jikesrvm.compilers.opt.ir.operand.LocationOperand; 060 import org.jikesrvm.compilers.opt.ir.operand.Operand; 061 import org.jikesrvm.compilers.opt.ir.operand.RegisterOperand; 062 import org.jikesrvm.compilers.opt.ir.operand.TrapCodeOperand; 063 064 /** 065 * Perform local common-subexpression elimination for a factored basic 066 * block. 067 * <ul> 068 * <li> Note: this module also performs scalar replacement of loads 069 * <li> Note: this module also performs elimination of redundant 070 * nullchecks, boundchecks, and zero checks. 071 * </ul> 072 * Algorithm: Muchnick pp.379-385 073 */ 074 public class LocalCSE extends CompilerPhase { 075 private final boolean isHIR; 076 077 /** 078 * Constructor 079 */ 080 public LocalCSE(boolean isHIR) { 081 super(new Object[]{isHIR}); 082 this.isHIR = isHIR; 083 } 084 085 /** 086 * Constructor for this compiler phase 087 */ 088 private static final Constructor<CompilerPhase> constructor = 089 getCompilerPhaseConstructor(LocalCSE.class, new Class[]{Boolean.TYPE}); 090 091 /** 092 * Get a constructor object for this compiler phase 093 * @return compiler phase constructor 094 */ 095 @Override 096 public Constructor<CompilerPhase> getClassConstructor() { 097 return constructor; 098 } 099 100 @Override 101 public final void reportAdditionalStats() { 102 VM.sysWrite(" "); 103 VM.sysWrite(container.counter1 / container.counter2 * 100, 2); 104 VM.sysWrite("% Infrequent BBs"); 105 } 106 107 @Override 108 public final boolean shouldPerform(OptOptions options) { 109 return options.LOCAL_CSE; 110 } 111 112 @Override 113 public final String getName() { 114 return "Local CSE"; 115 } 116 117 /** 118 * Perform Local CSE for a method. 119 * 120 * @param ir the IR to optimize 121 */ 122 @Override 123 public final void perform(IR ir) { 124 // iterate over each basic block 125 for (BasicBlock bb = ir.firstBasicBlockInCodeOrder(); bb != null; bb = bb.nextBasicBlockInCodeOrder()) { 126 if (bb.isEmpty()) continue; 127 container.counter2++; 128 if (bb.getInfrequent()) { 129 container.counter1++; 130 if (ir.options.FREQ_FOCUS_EFFORT) continue; 131 } 132 if (isHIR) { 133 optimizeBasicBlockHIR(ir, bb); 134 } else { 135 optimizeBasicBlockLIR(ir, bb); 136 } 137 } 138 } 139 140 /** 141 * Perform Local CSE for a basic block in HIR. 142 * 143 * @param ir the method's ir 144 * @param bb the basic block 145 */ 146 private void optimizeBasicBlockHIR(IR ir, BasicBlock bb) { 147 AvExCache cache = new AvExCache(ir.options, true); 148 // iterate over all instructions in the basic block 149 for (Instruction inst = bb.firstRealInstruction(), 150 sentinel = bb.lastInstruction(), 151 nextInstr = null; inst != sentinel; inst = nextInstr) { 152 nextInstr = inst.nextInstructionInCodeOrder(); // cache before we 153 // mutate prev/next links 154 // 1. try and replace this instruction according to 155 // available expressions in the cache, and update cache 156 // accordingly. 157 if (isLoadInstruction(inst)) { 158 loadHelper(ir, cache, inst); 159 } else if (isStoreInstruction(inst)) { 160 storeHelper(cache, inst); 161 } else if (isExpression(inst)) { 162 expressionHelper(ir, cache, inst); 163 } else if (isCheck(inst)) { 164 checkHelper(ir, cache, inst); 165 } else if (isTypeCheck(inst)) { 166 typeCheckHelper(ir, cache, inst); 167 } 168 169 // 2. update the cache according to which expressions this 170 // instruction kills 171 cache.eliminate(inst); 172 // Non-pure CALL instructions and synchronizations KILL all memory locations! 173 if (inst.isNonPureCall()) { 174 cache.invalidateAllLoads(); 175 } else if (isSynchronizing(inst) || inst.isDynamicLinkingPoint()) { 176 cache.invalidateAllLoads(); 177 } 178 } 179 } 180 181 /** 182 * Perform Local CSE for a basic block in LIR. 183 * 184 * @param ir the method's ir 185 * @param bb the basic block 186 */ 187 private void optimizeBasicBlockLIR(IR ir, BasicBlock bb) { 188 AvExCache cache = new AvExCache(ir.options, false); 189 // iterate over all instructions in the basic block 190 for (Instruction inst = bb.firstRealInstruction(), 191 sentinel = bb.lastInstruction(), 192 nextInstr = null; inst != sentinel; inst = nextInstr) { 193 nextInstr = inst.nextInstructionInCodeOrder(); // cache before we 194 // mutate prev/next links 195 // 1. try and replace this instruction according to 196 // available expressions in the cache, and update cache 197 // accordingly. 198 if (isExpression(inst)) { 199 expressionHelper(ir, cache, inst); 200 } else if (isCheck(inst)) { 201 checkHelper(ir, cache, inst); 202 } 203 204 // 2. update the cache according to which expressions this 205 // instruction kills 206 cache.eliminate(inst); 207 } 208 } 209 210 /** 211 * Is a given instruction a CSE-able load? 212 */ 213 public static boolean isLoadInstruction(Instruction s) { 214 return GetField.conforms(s) || GetStatic.conforms(s); 215 } 216 217 /** 218 * Is a given instruction a CSE-able store? 219 */ 220 public static boolean isStoreInstruction(Instruction s) { 221 return PutField.conforms(s) || PutStatic.conforms(s); 222 } 223 224 /** 225 * Does the instruction compute some expression? 226 * 227 * @param inst the instruction in question 228 * @return true or false, as appropriate 229 */ 230 private boolean isExpression(Instruction inst) { 231 if (inst.isDynamicLinkingPoint()) return false; 232 switch (inst.operator.format) { 233 case InstructionFormat.Unary_format: 234 case InstructionFormat.GuardedUnary_format: 235 case InstructionFormat.Binary_format: 236 case InstructionFormat.GuardedBinary_format: 237 case InstructionFormat.InstanceOf_format: 238 return true; 239 case InstructionFormat.Call_format: 240 return inst.isPureCall(); 241 default: 242 return false; 243 } 244 } 245 246 /** 247 * Is the given instruction a check instruction? 248 * 249 * @param inst the instruction in question 250 * @return true or false, as appropriate 251 */ 252 private boolean isCheck(Instruction inst) { 253 switch (inst.getOpcode()) { 254 case NULL_CHECK_opcode: 255 case BOUNDS_CHECK_opcode: 256 case INT_ZERO_CHECK_opcode: 257 case LONG_ZERO_CHECK_opcode: 258 return true; 259 case TRAP_IF_opcode: 260 TrapCodeOperand tc = TrapIf.getTCode(inst); 261 return tc.isNullPtr() || tc.isArrayBounds() || tc.isDivByZero(); 262 default: 263 return false; 264 } 265 } 266 267 private boolean isTypeCheck(Instruction inst) { 268 return TypeCheck.conforms(inst); 269 } 270 271 /** 272 * Process a load instruction 273 * 274 * @param ir the containing IR object. 275 * @param cache the cache of available expressions 276 * @param inst the instruction begin processed 277 */ 278 private void loadHelper(IR ir, AvExCache cache, Instruction inst) { 279 LocationOperand loc = LocationCarrier.getLocation(inst); 280 if (loc.mayBeVolatile()) return; // don't optimize volatile fields 281 282 // look up the expression in the cache 283 AvailableExpression ae = cache.find(inst); 284 if (ae != null) { 285 RegisterOperand dest = ResultCarrier.getClearResult(inst); 286 if (ae.tmp == null) { 287 // (1) generate a new temporary, and store in the AE cache 288 RegisterOperand newRes = ir.regpool.makeTemp(dest.getType()); 289 ae.tmp = newRes.getRegister(); 290 // (2) get the CSE value into newRes 291 if (ae.isLoad()) { 292 // the first appearance was a load. 293 // Modify the first load to assign its result to a new temporary 294 // and then insert a move from the new temporary to the old result 295 // after the mutated first load. 296 RegisterOperand res = ResultCarrier.getClearResult(ae.inst); 297 ResultCarrier.setResult(ae.inst, newRes); 298 ae.inst.insertAfter(Move.create(getMoveOp(res), res, newRes.copyD2U())); 299 } else { 300 // the first appearance was a store. 301 // Insert a move that assigns the value to newRes before 302 // the store instruction. 303 Operand value; 304 if (PutStatic.conforms(ae.inst)) { 305 value = PutStatic.getValue(ae.inst); 306 } else { 307 value = PutField.getValue(ae.inst); 308 } 309 ae.inst.insertBefore(Move.create(getMoveOp(newRes), newRes, value.copy())); 310 } 311 // (3) replace second load with a move from the new temporary 312 Move.mutate(inst, getMoveOp(dest), dest, newRes.copyD2U()); 313 } else { 314 // already have a temp. replace the load with a move 315 RegisterOperand newRes = new RegisterOperand(ae.tmp, dest.getType()); 316 Move.mutate(inst, getMoveOp(dest), dest, newRes); 317 } 318 } else { 319 // did not find a match: insert new entry in cache 320 cache.insert(inst); 321 } 322 } 323 324 /** 325 * Process a store instruction 326 * 327 * @param cache the cache of available expressions 328 * @param inst the instruction begin processed 329 */ 330 private void storeHelper(AvExCache cache, Instruction inst) { 331 LocationOperand loc = LocationCarrier.getLocation(inst); 332 if (loc.mayBeVolatile()) return; // don't optimize volatile fields 333 334 // look up the expression in the cache 335 AvailableExpression ae = cache.find(inst); 336 if (ae == null) { 337 // did not find a match: insert new entry in cache 338 cache.insert(inst); 339 } 340 } 341 342 /** 343 * Process a unary or binary expression. 344 * 345 * @param ir the containing IR object 346 * @param cache the cache of available expressions 347 * @param inst the instruction begin processed 348 */ 349 private void expressionHelper(IR ir, AvExCache cache, Instruction inst) { 350 // look up the expression in the cache 351 AvailableExpression ae = cache.find(inst); 352 if (ae != null) { 353 RegisterOperand dest = ResultCarrier.getClearResult(inst); 354 if (ae.tmp == null) { 355 // (1) generate a new temporary, and store in the AE cache 356 RegisterOperand newRes = ir.regpool.makeTemp(dest.getType()); 357 ae.tmp = newRes.getRegister(); 358 // (2) Modify ae.inst to assign its result to the new temporary 359 // and then insert a move from the new temporary to the old result 360 // of ae.inst after ae.inst. 361 RegisterOperand res = ResultCarrier.getClearResult(ae.inst); 362 ResultCarrier.setResult(ae.inst, newRes); 363 ae.inst.insertAfter(Move.create(getMoveOp(res), res, newRes.copyD2U())); 364 // (3) replace inst with a move from the new temporary 365 Move.mutate(inst, getMoveOp(dest), dest, newRes.copyD2U()); 366 } else { 367 // already have a temp. replace inst with a move 368 RegisterOperand newRes = new RegisterOperand(ae.tmp, dest.getType()); 369 Move.mutate(inst, getMoveOp(dest), dest, newRes); 370 } 371 } else { 372 // did not find a match: insert new entry in cache 373 cache.insert(inst); 374 } 375 } 376 377 /** 378 * Process a check instruction 379 * 380 * @param cache the cache of available expressions 381 * @param inst the instruction begin processed 382 */ 383 private void checkHelper(IR ir, AvExCache cache, Instruction inst) { 384 // look up the check in the cache 385 AvailableExpression ae = cache.find(inst); 386 if (ae != null) { 387 RegisterOperand dest = GuardResultCarrier.getClearGuardResult(inst); 388 if (ae.tmp == null) { 389 // generate a new temporary, and store in the AE cache 390 RegisterOperand newRes = ir.regpool.makeTemp(dest.getType()); 391 ae.tmp = newRes.getRegister(); 392 // (2) Modify ae.inst to assign its guard result to the new temporary 393 // and then insert a guard move from the new temporary to the 394 // old guard result of ae.inst after ae.inst. 395 RegisterOperand res = GuardResultCarrier.getClearGuardResult(ae.inst); 396 GuardResultCarrier.setGuardResult(ae.inst, newRes); 397 ae.inst.insertAfter(Move.create(GUARD_MOVE, res, newRes.copyD2U())); 398 // (3) replace inst with a move from the new temporary 399 Move.mutate(inst, GUARD_MOVE, dest, newRes.copyD2U()); 400 } else { 401 // already have a temp. replace inst with a guard move 402 RegisterOperand newRes = new RegisterOperand(ae.tmp, dest.getType()); 403 Move.mutate(inst, GUARD_MOVE, dest, newRes); 404 } 405 } else { 406 // did not find a match: insert new entry in cache 407 cache.insert(inst); 408 } 409 } 410 411 /** 412 * Process a type check instruction 413 * 414 * @param ir Unused 415 * @param cache The cache of available expressions. 416 * @param inst The instruction being processed 417 */ 418 private static void typeCheckHelper(IR ir, AvExCache cache, Instruction inst) { 419 // look up the check in the cache 420 AvailableExpression ae = cache.find(inst); 421 if (ae != null) { 422 // it's a duplicate; blow it away. 423 Move.mutate(inst, REF_MOVE, TypeCheck.getClearResult(inst), TypeCheck.getClearRef(inst)); 424 } else { 425 // did not find a match: insert new entry in cache 426 cache.insert(inst); 427 } 428 } 429 430 private static Operator getMoveOp(RegisterOperand r) { 431 return IRTools.getMoveOp(r.getType()); 432 } 433 434 /** 435 * Is this a synchronizing instruction? 436 * 437 * @param inst the instruction in question 438 */ 439 private static boolean isSynchronizing(Instruction inst) { 440 switch (inst.getOpcode()) { 441 case MONITORENTER_opcode: 442 case MONITOREXIT_opcode: 443 case READ_CEILING_opcode: 444 case WRITE_FLOOR_opcode: 445 return true; 446 default: 447 return false; 448 } 449 } 450 451 /** 452 * Implements a cache of Available Expressions 453 */ 454 protected static final class AvExCache { 455 /** Implementation of the cache */ 456 private final ArrayList<AvailableExpression> cache = new ArrayList<AvailableExpression>(3); 457 458 private final OptOptions options; 459 private final boolean doMemory; 460 461 AvExCache(OptOptions opts, boolean doMem) { 462 options = opts; 463 doMemory = doMem; 464 } 465 466 /** 467 * Find and return a matching available expression. 468 * 469 * @param inst the instruction to match 470 * @return the matching AE if found, null otherwise 471 */ 472 public AvailableExpression find(Instruction inst) { 473 Operator opr = inst.operator(); 474 Operand[] ops = null; 475 LocationOperand location = null; 476 switch (inst.operator.format) { 477 case InstructionFormat.GetField_format: 478 if (VM.VerifyAssertions) VM._assert(doMemory); 479 ops = new Operand[]{GetField.getRef(inst)}; 480 location = GetField.getLocation(inst); 481 break; 482 case InstructionFormat.GetStatic_format: 483 if (VM.VerifyAssertions) VM._assert(doMemory); 484 location = GetStatic.getLocation(inst); 485 break; 486 case InstructionFormat.PutField_format: 487 if (VM.VerifyAssertions) VM._assert(doMemory); 488 ops = new Operand[]{PutField.getRef(inst)}; 489 location = PutField.getLocation(inst); 490 break; 491 case InstructionFormat.PutStatic_format: 492 if (VM.VerifyAssertions) VM._assert(doMemory); 493 location = PutStatic.getLocation(inst); 494 break; 495 case InstructionFormat.Unary_format: 496 ops = new Operand[]{Unary.getVal(inst)}; 497 break; 498 case InstructionFormat.GuardedUnary_format: 499 ops = new Operand[]{GuardedUnary.getVal(inst)}; 500 break; 501 case InstructionFormat.Binary_format: 502 ops = new Operand[]{Binary.getVal1(inst), Binary.getVal2(inst)}; 503 break; 504 case InstructionFormat.GuardedBinary_format: 505 ops = new Operand[]{GuardedBinary.getVal1(inst), GuardedBinary.getVal2(inst)}; 506 break; 507 case InstructionFormat.Move_format: 508 ops = new Operand[]{Move.getVal(inst)}; 509 break; 510 case InstructionFormat.NullCheck_format: 511 ops = new Operand[]{NullCheck.getRef(inst)}; 512 break; 513 case InstructionFormat.ZeroCheck_format: 514 ops = new Operand[]{ZeroCheck.getValue(inst)}; 515 break; 516 case InstructionFormat.BoundsCheck_format: 517 ops = new Operand[]{BoundsCheck.getRef(inst), BoundsCheck.getIndex(inst)}; 518 break; 519 case InstructionFormat.TrapIf_format: 520 ops = new Operand[]{TrapIf.getVal1(inst), TrapIf.getVal2(inst), TrapIf.getTCode(inst)}; 521 break; 522 case InstructionFormat.TypeCheck_format: 523 ops = new Operand[]{TypeCheck.getRef(inst), TypeCheck.getType(inst)}; 524 break; 525 case InstructionFormat.InstanceOf_format: 526 ops = new Operand[]{InstanceOf.getRef(inst), InstanceOf.getType(inst)}; 527 break; 528 case InstructionFormat.Call_format: 529 int numParams = Call.getNumberOfParams(inst); 530 ops = new Operand[numParams+2]; 531 ops[0] = Call.getAddress(inst); 532 ops[1] = Call.getMethod(inst); 533 for (int i=0; i < numParams; i++) { 534 ops[i+2] = Call.getParam(inst, i); 535 } 536 break; 537 default: 538 throw new OptimizingCompilerException("Unsupported type " + inst); 539 } 540 541 AvailableExpression ae = new AvailableExpression(inst, opr, ops, location, null); 542 int index = cache.indexOf(ae); 543 if (index == -1) { 544 return null; 545 } 546 return cache.get(index); 547 } 548 549 /** 550 * Insert a new available expression in the cache 551 * 552 * @param inst the instruction that defines the AE 553 */ 554 public void insert(Instruction inst) { 555 Operator opr = inst.operator(); 556 Operand[] ops = null; 557 LocationOperand location = null; 558 559 switch (inst.operator.format) { 560 case InstructionFormat.GetField_format: 561 if (VM.VerifyAssertions) VM._assert(doMemory); 562 ops = new Operand[]{GetField.getRef(inst)}; 563 location = GetField.getLocation(inst); 564 break; 565 case InstructionFormat.GetStatic_format: 566 if (VM.VerifyAssertions) VM._assert(doMemory); 567 location = GetStatic.getLocation(inst); 568 break; 569 case InstructionFormat.PutField_format: 570 if (VM.VerifyAssertions) VM._assert(doMemory); 571 ops = new Operand[]{PutField.getRef(inst)}; 572 location = PutField.getLocation(inst); 573 break; 574 case InstructionFormat.PutStatic_format: 575 if (VM.VerifyAssertions) VM._assert(doMemory); 576 location = PutStatic.getLocation(inst); 577 break; 578 case InstructionFormat.Unary_format: 579 ops = new Operand[]{Unary.getVal(inst)}; 580 break; 581 case InstructionFormat.GuardedUnary_format: 582 ops = new Operand[]{GuardedUnary.getVal(inst)}; 583 break; 584 case InstructionFormat.Binary_format: 585 ops = new Operand[]{Binary.getVal1(inst), Binary.getVal2(inst)}; 586 break; 587 case InstructionFormat.GuardedBinary_format: 588 ops = new Operand[]{GuardedBinary.getVal1(inst), GuardedBinary.getVal2(inst)}; 589 break; 590 case InstructionFormat.Move_format: 591 ops = new Operand[]{Move.getVal(inst)}; 592 break; 593 case InstructionFormat.NullCheck_format: 594 ops = new Operand[]{NullCheck.getRef(inst)}; 595 break; 596 case InstructionFormat.ZeroCheck_format: 597 ops = new Operand[]{ZeroCheck.getValue(inst)}; 598 break; 599 case InstructionFormat.BoundsCheck_format: 600 ops = new Operand[]{BoundsCheck.getRef(inst), BoundsCheck.getIndex(inst)}; 601 break; 602 case InstructionFormat.TrapIf_format: 603 ops = new Operand[]{TrapIf.getVal1(inst), TrapIf.getVal2(inst), TrapIf.getTCode(inst)}; 604 break; 605 case InstructionFormat.TypeCheck_format: 606 ops = new Operand[]{TypeCheck.getRef(inst), TypeCheck.getType(inst)}; 607 break; 608 case InstructionFormat.InstanceOf_format: 609 ops = new Operand[]{InstanceOf.getRef(inst), InstanceOf.getType(inst)}; 610 break; 611 case InstructionFormat.Call_format: 612 int numParams = Call.getNumberOfParams(inst); 613 ops = new Operand[numParams+2]; 614 ops[0] = Call.getAddress(inst); 615 ops[1] = Call.getMethod(inst); 616 for (int i=0; i < numParams; i++) { 617 ops[i+2] = Call.getParam(inst, i); 618 } 619 break; 620 default: 621 throw new OptimizingCompilerException("Unsupported type " + inst); 622 } 623 624 AvailableExpression ae = new AvailableExpression(inst, opr, ops, location, null); 625 cache.add(ae); 626 } 627 628 /** 629 * Eliminate all AE tuples that contain a given operand 630 * 631 * @param op the operand in question 632 */ 633 private void eliminate(RegisterOperand op) { 634 int i = 0; 635 loop_over_expressions: 636 while (i < cache.size()) { 637 AvailableExpression ae = cache.get(i); 638 if (ae.ops != null) { 639 for (Operand opx : ae.ops) { 640 if (opx instanceof RegisterOperand && ((RegisterOperand) opx).getRegister() == op.getRegister()) { 641 cache.remove(i); 642 continue loop_over_expressions; // don't increment i, since we removed 643 } 644 } 645 } 646 i++; 647 } 648 } 649 650 /** 651 * Eliminate all AE tuples that are killed by a given instruction 652 * 653 * @param s the store instruction 654 */ 655 public void eliminate(Instruction s) { 656 int i = 0; 657 // first kill all registers that this instruction defs 658 for (Enumeration<Operand> defs = s.getDefs(); defs.hasMoreElements();) { 659 // first KILL any registers this instruction DEFS 660 Operand def = defs.nextElement(); 661 if (def instanceof RegisterOperand) { 662 eliminate((RegisterOperand) def); 663 } 664 } 665 if (doMemory) { 666 // eliminate all memory locations killed by stores 667 if (LocalCSE.isStoreInstruction(s) || (options.READS_KILL && LocalCSE.isLoadInstruction(s))) { 668 // sLocation holds the location killed by this instruction 669 LocationOperand sLocation = LocationCarrier.getLocation(s); 670 // walk through the cache and invalidate any killed locations 671 while (i < cache.size()) { 672 AvailableExpression ae = cache.get(i); 673 if (ae.inst != s) { // a store instruction doesn't kill itself 674 boolean killIt = false; 675 if (ae.isLoadOrStore()) { 676 if ((sLocation == null) && (ae.location == null)) { 677 // !TODO: is this too conservative?? 678 killIt = true; 679 } else if ((sLocation != null) && (ae.location != null)) { 680 killIt = LocationOperand.mayBeAliased(sLocation, ae.location); 681 } 682 } 683 if (killIt) { 684 cache.remove(i); 685 continue; // don't increment i, since we removed 686 } 687 } 688 i++; 689 } 690 } 691 } 692 } 693 694 /** 695 * Eliminate all AE tuples that cache ANY memory location. 696 */ 697 public void invalidateAllLoads() { 698 if (!doMemory) return; 699 int i = 0; 700 while (i < cache.size()) { 701 AvailableExpression ae = cache.get(i); 702 if (ae.isLoadOrStore()) { 703 cache.remove(i); 704 continue; // don't increment i, since we removed 705 } 706 i++; 707 } 708 } 709 } 710 711 /** 712 * A tuple to record an Available Expression 713 */ 714 private static final class AvailableExpression { 715 /** 716 * the instruction which makes this expression available 717 */ 718 final Instruction inst; 719 /** 720 * the operator of the expression 721 */ 722 final Operator opr; 723 /** 724 * operands 725 */ 726 final Operand[] ops; 727 /** 728 * location operand for memory (load/store) expressions 729 */ 730 final LocationOperand location; 731 /** 732 * temporary register holding the result of the available 733 * expression 734 */ 735 Register tmp; 736 737 /** 738 * @param i the instruction which makes this expression available 739 * @param op the operator of the expression 740 * @param ops the operands 741 * @param loc location operand for memory (load/store) expressions 742 * @param t temporary register holding the result of the available 743 * expression 744 */ 745 AvailableExpression(Instruction i, Operator op, Operand[] ops, 746 LocationOperand loc, Register t) { 747 this.inst = i; 748 this.opr = op; 749 this.ops = ops; 750 this.location = loc; 751 this.tmp = t; 752 } 753 754 /** 755 * Two AEs are "equal" iff 756 * <ul> 757 * <li> for unary, binary and ternary expressions: 758 * the operator and the operands match 759 * <li> for loads and stores: if the 2 operands and the location match 760 * </ul> 761 */ 762 @Override 763 public boolean equals(Object o) { 764 if (!(o instanceof AvailableExpression)) { 765 return false; 766 } 767 AvailableExpression ae = (AvailableExpression) o; 768 if (isLoadOrStore()) { 769 if (!ae.isLoadOrStore()) { 770 return false; 771 } 772 boolean result = LocationOperand.mayBeAliased(location, ae.location); 773 if (ops == null || ae.ops == null){ 774 return result && ops == ae.ops; 775 } 776 result = result && ops[0].similar(ae.ops[0]); 777 if (ops.length > 1) { 778 result = result && ops[1].similar(ae.ops[1]); 779 } else { 780 /* ops[1] isn't present, so ae.ops[1] must also not be present */ 781 if (ae.ops.length > 1) { 782 return false; 783 } 784 } 785 return result; 786 } else if (isBoundsCheck()) { 787 // Augment equality with BC(ref,C1) ==> BC(ref,C2) 788 // when C1>0, C2>=0, and C1>C2 789 if (!opr.equals(ae.opr)) { 790 return false; 791 } 792 if (!ops[0].similar(ae.ops[0])) { 793 return false; 794 } 795 if (ops[1].similar(ae.ops[1])) { 796 return true; 797 } 798 if (ops[1] instanceof IntConstantOperand && ae.ops[1] instanceof IntConstantOperand) { 799 int C1 = ((IntConstantOperand) ops[1]).value; 800 int C2 = ((IntConstantOperand) ae.ops[1]).value; 801 return C1 > 0 && C2 >= 0 && C1 > C2; 802 } else { 803 return false; 804 } 805 } else { 806 if (!opr.equals(ae.opr)) { 807 return false; 808 } 809 if (ops.length != ae.ops.length) { 810 return false; 811 } else { 812 if (ops.length == 2) { 813 return (ops[0].similar(ae.ops[0]) && ops[1].similar(ae.ops[1])) || 814 (isCommutative() && ops[0].similar(ae.ops[1]) && ops[1].similar(ae.ops[0])); 815 } else { 816 for (int i=0; i < ops.length; i++) { 817 if (!ops[i].similar(ae.ops[i])) { 818 return false; 819 } 820 } 821 return true; 822 } 823 } 824 } 825 } 826 /** 827 * Unused hashcode method 828 */ 829 @Override 830 public int hashCode() { 831 return opr.hashCode(); 832 } 833 834 /** 835 * Does this expression represent the result of a load or store? 836 */ 837 public boolean isLoadOrStore() { 838 return GetField.conforms(opr) || GetStatic.conforms(opr) || PutField.conforms(opr) || PutStatic.conforms(opr); 839 } 840 841 /** 842 * Does this expression represent the result of a load? 843 */ 844 public boolean isLoad() { 845 return GetField.conforms(opr) || GetStatic.conforms(opr); 846 } 847 848 /** 849 * Does this expression represent the result of a store? 850 */ 851 public boolean isStore() { 852 return PutField.conforms(opr) || PutStatic.conforms(opr); 853 } 854 855 /** 856 * Does this expression represent the result of a bounds check? 857 */ 858 private boolean isBoundsCheck() { 859 return BoundsCheck.conforms(opr) || (TrapIf.conforms(opr) && ((TrapCodeOperand) ops[2]).isArrayBounds()); 860 } 861 862 /** 863 * Is this expression commutative? 864 */ 865 private boolean isCommutative() { 866 return opr.isCommutative(); 867 } 868 } 869 }