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.ir; 014 015 import java.util.Enumeration; 016 import org.jikesrvm.ArchitectureSpecificOpt.RegisterPool; 017 import org.jikesrvm.Configuration; 018 import org.jikesrvm.classloader.FieldReference; 019 import org.jikesrvm.classloader.TypeReference; 020 import org.jikesrvm.compilers.opt.ir.operand.AddressConstantOperand; 021 import org.jikesrvm.compilers.opt.ir.operand.BranchOperand; 022 import org.jikesrvm.compilers.opt.ir.operand.DoubleConstantOperand; 023 import org.jikesrvm.compilers.opt.ir.operand.FloatConstantOperand; 024 import org.jikesrvm.compilers.opt.ir.operand.IntConstantOperand; 025 import org.jikesrvm.compilers.opt.ir.operand.LongConstantOperand; 026 import org.jikesrvm.compilers.opt.ir.operand.NullConstantOperand; 027 import org.jikesrvm.compilers.opt.ir.operand.Operand; 028 import org.jikesrvm.compilers.opt.ir.operand.RegisterOperand; 029 import org.jikesrvm.compilers.opt.ir.operand.TrueGuardOperand; 030 031 import static org.jikesrvm.compilers.opt.ir.Operators.BYTE_LOAD; 032 import static org.jikesrvm.compilers.opt.ir.Operators.BYTE_STORE; 033 import static org.jikesrvm.compilers.opt.ir.Operators.DOUBLE_COND_MOVE; 034 import static org.jikesrvm.compilers.opt.ir.Operators.DOUBLE_LOAD; 035 import static org.jikesrvm.compilers.opt.ir.Operators.DOUBLE_MOVE; 036 import static org.jikesrvm.compilers.opt.ir.Operators.DOUBLE_STORE; 037 import static org.jikesrvm.compilers.opt.ir.Operators.FLOAT_COND_MOVE; 038 import static org.jikesrvm.compilers.opt.ir.Operators.FLOAT_LOAD; 039 import static org.jikesrvm.compilers.opt.ir.Operators.FLOAT_MOVE; 040 import static org.jikesrvm.compilers.opt.ir.Operators.FLOAT_STORE; 041 import static org.jikesrvm.compilers.opt.ir.Operators.GOTO; 042 import static org.jikesrvm.compilers.opt.ir.Operators.GUARD_COND_MOVE; 043 import static org.jikesrvm.compilers.opt.ir.Operators.GUARD_MOVE; 044 import static org.jikesrvm.compilers.opt.ir.Operators.INT_COND_MOVE; 045 import static org.jikesrvm.compilers.opt.ir.Operators.INT_LOAD; 046 import static org.jikesrvm.compilers.opt.ir.Operators.INT_MOVE; 047 import static org.jikesrvm.compilers.opt.ir.Operators.INT_STORE; 048 import static org.jikesrvm.compilers.opt.ir.Operators.LONG_COND_MOVE; 049 import static org.jikesrvm.compilers.opt.ir.Operators.LONG_LOAD; 050 import static org.jikesrvm.compilers.opt.ir.Operators.LONG_MOVE; 051 import static org.jikesrvm.compilers.opt.ir.Operators.LONG_STORE; 052 import static org.jikesrvm.compilers.opt.ir.Operators.REF_COND_MOVE; 053 import static org.jikesrvm.compilers.opt.ir.Operators.REF_LOAD; 054 import static org.jikesrvm.compilers.opt.ir.Operators.REF_MOVE; 055 import static org.jikesrvm.compilers.opt.ir.Operators.REF_STORE; 056 import static org.jikesrvm.compilers.opt.ir.Operators.SHORT_LOAD; 057 import static org.jikesrvm.compilers.opt.ir.Operators.SHORT_STORE; 058 import static org.jikesrvm.compilers.opt.ir.Operators.UBYTE_LOAD; 059 import static org.jikesrvm.compilers.opt.ir.Operators.USHORT_LOAD; 060 import org.vmmagic.unboxed.Address; 061 import org.vmmagic.unboxed.Offset; 062 063 /** 064 * This abstract class contains a bunch of useful static methods for 065 * performing operations on IR. 066 */ 067 public abstract class IRTools { 068 069 /** 070 * Create an integer register operand for a given register. 071 * To be used in passthrough expressions like 072 * <pre> 073 * ... Load.create(INT_LOAD, I(r2), A(r1), IC(4)) ... 074 * </pre> 075 * 076 * @param reg the given register 077 * @return integer register operand 078 */ 079 public static RegisterOperand A(Register reg) { 080 return new RegisterOperand(reg, TypeReference.Address); 081 } 082 083 /** 084 * Create an integer register operand for a given register. 085 * To be used in passthrough expressions like 086 * <pre> 087 * ... Load.create(INT_LOAD, I(r2), A(r1), IC(4)) ... 088 * </pre> 089 * @param reg the given register 090 * @return integer register operand 091 */ 092 public static RegisterOperand I(Register reg) { 093 return new RegisterOperand(reg, TypeReference.Int); 094 } 095 096 /** 097 * Create a float register operand for a given register. 098 * To be used in passthrough expressions like 099 * <pre> 100 * ... Load.create(FLOAT_LOAD, F(r2), A(r1), IC(4)) ... 101 * </pre> 102 * 103 * @param reg the given register 104 * @return float register operand 105 */ 106 public static RegisterOperand F(Register reg) { 107 return new RegisterOperand(reg, TypeReference.Float); 108 } 109 110 /** 111 * Create a double register operand for a given register. 112 * To be used in passthrough expressions like 113 * <pre> 114 * ... Load.create(DOUBLE_LOAD, D(r2), A(r1), IC(4)) ... 115 * </pre> 116 * 117 * @param reg the given register 118 * @return double register operand 119 */ 120 public static RegisterOperand D(Register reg) { 121 return new RegisterOperand(reg, TypeReference.Double); 122 } 123 124 /** 125 * Create a long register operand for a given register. 126 * To be used in passthrough expressions like 127 * <pre> 128 * ... Binary.create(LONG_LOAD, L(r2), A(r1), IC(4)) ... 129 * </pre> 130 * 131 * @param reg the given register 132 * @return long register operand 133 */ 134 public static RegisterOperand L(Register reg) { 135 return new RegisterOperand(reg, TypeReference.Long); 136 } 137 138 /** 139 * Create a condition register operand for a given register. 140 * To be used in passthrough expressions like 141 * <pre> 142 * ... Binary.create(INT_CMP, CR(c2), I(r1), IC(4)) ... 143 * </pre> 144 * 145 * @param reg the given register 146 * @return condition register operand 147 */ 148 public static RegisterOperand CR(Register reg) { 149 return new RegisterOperand(reg, TypeReference.Int); 150 } 151 152 /** 153 * Create an address constant operand with a given value. 154 * To be used in passthrough expressions like 155 * <pre> 156 * ...<op>.create(...., AC(Address.zero()) ... 157 * </pre> 158 * 159 * @param value The address constant 160 * @return address constant operand 161 */ 162 public static AddressConstantOperand AC(Address value) { 163 return new AddressConstantOperand(value); 164 } 165 166 public static AddressConstantOperand AC(Offset value) { 167 return new AddressConstantOperand(value); 168 } 169 170 /** 171 * Create an integer constant operand with a given value. 172 * To be used in passthrough expressions like 173 * <pre> 174 * ...<op>.create(...., IC(0) ... 175 * </pre> 176 * 177 * @param value The int constant 178 * @return integer constant operand 179 */ 180 public static IntConstantOperand IC(int value) { 181 return new IntConstantOperand(value); 182 } 183 184 /** 185 * Create a long constant operand with a given value. 186 * To be used in passthrough expressions like 187 * <pre> 188 * ...<op>.create(...., LC(0L) ... 189 * </pre> 190 * 191 * @param value the long value 192 * @return long constant operand 193 */ 194 public static LongConstantOperand LC(long value) { 195 return new LongConstantOperand(value); 196 } 197 198 /** 199 * Create a long constant operand with a given value. 200 * To be used in passthrough expressions like 201 * <pre> 202 * ...<op>.create(...., FC(0L) ... 203 * </pre> 204 * 205 * @param value the float value 206 * @return float constant operand 207 */ 208 public static FloatConstantOperand FC(float value) { 209 return new FloatConstantOperand(value); 210 } 211 212 /** 213 * Create a long constant operand with a given value. 214 * To be used in passthrough expressions like 215 * <pre> 216 * ...<op>.create(...., DC(0L) ... 217 * </pre> 218 * 219 * @param value the double value 220 * @return double constant operand 221 */ 222 public static DoubleConstantOperand DC(double value) { 223 return new DoubleConstantOperand(value); 224 } 225 226 /** 227 * Create a new TrueGuardOperand. 228 * To be used in passthrough expressions like 229 * <pre> 230 * ...<op>.create(...., TG() ... 231 * </pre> 232 * 233 * @return true guard operand 234 */ 235 public static TrueGuardOperand TG() { 236 return new TrueGuardOperand(); 237 } 238 239 /** 240 * Copy the position information from the source instruction to 241 * the destination instruction, returning the source instruction. 242 * To be used in passthrough expressions like 243 * <pre> 244 * instr.insertBack(CPOS(instr, Load.create(...))); 245 * </pre> 246 * 247 * @param src the instruction to copy position information from 248 * @param dst the instruction to copy position information to 249 * @return dest 250 */ 251 public static Instruction CPOS(Instruction src, Instruction dst) { 252 dst.copyPosition(src); 253 return dst; 254 } 255 256 /** 257 * Returns a constant operand with a default value for a given type 258 * 259 * @param type desired type 260 * @return a constant operand with the default value for type 261 */ 262 public static Operand getDefaultOperand(TypeReference type) { 263 if (type.isBooleanType()) return new IntConstantOperand(0); 264 if (type.isByteType()) return new IntConstantOperand(0); 265 if (type.isCharType()) return new IntConstantOperand(0); 266 if (type.isIntType()) return new IntConstantOperand(0); 267 if (type.isShortType()) return new IntConstantOperand(0); 268 if (type.isLongType()) return new LongConstantOperand(0); 269 if (type.isFloatType()) return new FloatConstantOperand(0f); 270 if (type.isDoubleType()) return new DoubleConstantOperand(0.0); 271 return new NullConstantOperand(); 272 } 273 274 /** 275 * Returns the correct operator for moving the given data type. 276 * 277 * @param type desired type to move 278 * @return the Operator to use for moving a value of the given type 279 */ 280 public static Operator getMoveOp(TypeReference type) { 281 if (type.isLongType()) return LONG_MOVE; 282 if (type.isFloatType()) return FLOAT_MOVE; 283 if (type.isDoubleType()) return DOUBLE_MOVE; 284 if (type == TypeReference.VALIDATION_TYPE) return GUARD_MOVE; 285 if (type.isReferenceType() || type.isWordLikeType()) return REF_MOVE; 286 return INT_MOVE; 287 } 288 289 /** 290 * Returns the correct operator for a conditional move with the given data 291 * type. 292 * 293 * @param type desired type to move 294 * @return the Operator to use for moving a value of the given type 295 */ 296 public static Operator getCondMoveOp(TypeReference type) { 297 if (type.isLongType()) return LONG_COND_MOVE; 298 if (type.isFloatType()) return FLOAT_COND_MOVE; 299 if (type.isDoubleType()) return DOUBLE_COND_MOVE; 300 if (type == TypeReference.VALIDATION_TYPE) return GUARD_COND_MOVE; 301 if (type.isReferenceType() || type.isWordLikeType()) return REF_COND_MOVE; 302 return INT_COND_MOVE; 303 } 304 305 /** 306 * Returns the correct operator for loading from the given field 307 * 308 * @param field field to load from 309 * @param isStatic is the field static 310 * @return the Operator to use when loading the given field 311 */ 312 public static Operator getLoadOp(FieldReference field, boolean isStatic) { 313 return getLoadOp(field.getFieldContentsType(), isStatic); 314 } 315 316 /** 317 * Returns the correct operator for loading a value of the given type 318 * 319 * @param type type of value to load 320 * @param isStatic is the field static 321 * @return the Operator to use when loading the given field 322 */ 323 public static Operator getLoadOp(TypeReference type, boolean isStatic) { 324 if (!Configuration.LittleEndian && isStatic) { 325 // Handle the statics table hold subword values in ints 326 if (type.isByteType()) return INT_LOAD; 327 if (type.isBooleanType()) return INT_LOAD; 328 if (type.isCharType()) return INT_LOAD; 329 if (type.isShortType()) return INT_LOAD; 330 } 331 if (type.isByteType()) return BYTE_LOAD; 332 if (type.isBooleanType()) return UBYTE_LOAD; 333 if (type.isCharType()) return USHORT_LOAD; 334 if (type.isShortType()) return SHORT_LOAD; 335 if (type.isLongType()) return LONG_LOAD; 336 if (type.isFloatType()) return FLOAT_LOAD; 337 if (type.isDoubleType()) return DOUBLE_LOAD; 338 if (type.isReferenceType()) return REF_LOAD; 339 if (type.isWordLikeType()) return REF_LOAD; 340 return INT_LOAD; 341 } 342 343 /** 344 * Returns the correct operator for storing to the given field. 345 * 346 * @param field The field we're asking about 347 * @param isStatic is the field static 348 * @return the Operator to use when storing to the given field 349 */ 350 public static Operator getStoreOp(FieldReference field, boolean isStatic) { 351 return getStoreOp(field.getFieldContentsType(), isStatic); 352 } 353 354 /** 355 * Returns the correct operator for storing a value of the given type 356 * 357 * @param type desired type to store 358 * @param isStatic is the field static 359 * @return the Operator to use when storing to the given field 360 */ 361 public static Operator getStoreOp(TypeReference type, boolean isStatic) { 362 if (!Configuration.LittleEndian && isStatic) { 363 // Handle the statics table hold subword values in ints 364 if (type.isByteType()) return INT_STORE; 365 if (type.isBooleanType()) return INT_STORE; 366 if (type.isCharType()) return INT_STORE; 367 if (type.isShortType()) return INT_STORE; 368 } 369 if (type.isByteType()) return BYTE_STORE; 370 if (type.isBooleanType()) return BYTE_STORE; 371 if (type.isCharType()) return SHORT_STORE; 372 if (type.isShortType()) return SHORT_STORE; 373 if (type.isLongType()) return LONG_STORE; 374 if (type.isFloatType()) return FLOAT_STORE; 375 if (type.isDoubleType()) return DOUBLE_STORE; 376 if (type.isReferenceType()) return REF_STORE; 377 if (type.isWordLikeType()) return REF_STORE; 378 return INT_STORE; 379 } 380 381 /** 382 * Generates an instruction to move the given operand into a register, and 383 * inserts it before the given instruction. 384 * 385 * @param pool register pool to allocate from 386 * @param s instruction to insert before 387 * @param op operand to copy to a register 388 * @return register operand that we copied into 389 */ 390 public static RegisterOperand moveIntoRegister(RegisterPool pool, Instruction s, Operand op) { 391 if (op instanceof RegisterOperand) { 392 return (RegisterOperand) op; 393 } 394 TypeReference type = op.getType(); 395 Operator move_op = IRTools.getMoveOp(type); 396 return moveIntoRegister(type, move_op, pool, s, op); 397 } 398 399 /** 400 * Generates an instruction to move the given operand into a register, and 401 * inserts it before the given instruction. 402 * 403 * @param type type to move 404 * @param move_op move operator to use 405 * @param pool register pool to allocate from 406 * @param s instruction to insert before 407 * @param op operand to copy to a register 408 * @return last use register operand that we copied into 409 */ 410 public static RegisterOperand moveIntoRegister(TypeReference type, Operator move_op, RegisterPool pool, 411 Instruction s, Operand op) { 412 RegisterOperand rop = pool.makeTemp(type); 413 s.insertBefore(Move.create(move_op, rop, op)); 414 rop = rop.copyD2U(); 415 return rop; 416 } 417 418 /** 419 * Moves the 'from' instruction to immediately before the 'to' instruction. 420 * 421 * @param from instruction to move 422 * @param to instruction after where you want it moved 423 */ 424 public static void moveInstruction(Instruction from, Instruction to) { 425 from.remove(); 426 to.insertBefore(from); 427 } 428 429 /** 430 * Inserts the instructions in the given basic block after the given 431 * instruction. 432 * 433 * @param after instruction after where you want it inserted 434 * @param temp basic block which contains the instructions to be inserted. 435 */ 436 public static void insertInstructionsAfter(Instruction after, BasicBlock temp) { 437 if (temp.isEmpty()) return; 438 Instruction after_after = after.getNext(); 439 after.linkWithNext(temp.firstRealInstruction()); 440 if (after_after == null) { 441 temp.lastRealInstruction().setNext(null); 442 } else { 443 temp.lastRealInstruction().linkWithNext(after_after); 444 } 445 } 446 447 /** 448 * Make an empty basic block on an edge in the control flow graph, 449 * and fix up the control flow graph and IR instructions accordingly. 450 * 451 * This routine will create the control struture 452 * <pre> 453 * in -> bb -> out. 454 * </pre> 455 * <em> Precondition </em>: There is an edge in the control flow graph 456 * from * in -> out. 457 * 458 * @param in the source of the control flow edge 459 * @param out the sink of the control flow edge 460 * @param ir the governing IR 461 * @return the new basic block bb 462 */ 463 public static BasicBlock makeBlockOnEdge(BasicBlock in, BasicBlock out, IR ir) { 464 // 1. Create the new basic block 465 BasicBlock bb = in.createSubBlock(out.firstInstruction().bcIndex, ir); 466 467 // 2. Splice the new basic block into the code order 468 BasicBlock next = in.nextBasicBlockInCodeOrder(); 469 if (next == null) { 470 ir.cfg.addLastInCodeOrder(bb); 471 } else { 472 ir.cfg.breakCodeOrder(in, next); 473 ir.cfg.linkInCodeOrder(in, bb); 474 ir.cfg.linkInCodeOrder(bb, next); 475 } 476 477 // 3. update in's branch instructions 478 boolean foundGoto = false; 479 BranchOperand target = bb.makeJumpTarget(); 480 BranchOperand outTarget = out.makeJumpTarget(); 481 for (Enumeration<Instruction> e = in.reverseRealInstrEnumerator(); e.hasMoreElements();) { 482 Instruction s = e.nextElement(); 483 if (IfCmp2.conforms(s)) { 484 if (IfCmp2.getTarget1(s).similar(outTarget)) { 485 IfCmp2.setTarget1(s, (BranchOperand) target.copy()); 486 } 487 if (IfCmp2.getTarget2(s).similar(outTarget)) { 488 IfCmp2.setTarget2(s, (BranchOperand) target.copy()); 489 } 490 } else if (IfCmp.conforms(s)) { 491 if (IfCmp.getTarget(s).similar(outTarget)) { 492 IfCmp.setTarget(s, (BranchOperand) target.copy()); 493 } 494 } else if (InlineGuard.conforms(s)) { 495 if (InlineGuard.getTarget(s).similar(outTarget)) { 496 InlineGuard.setTarget(s, (BranchOperand) target.copy()); 497 } 498 } else if (Goto.conforms(s)) { 499 foundGoto = true; 500 if (Goto.getTarget(s).similar(outTarget)) { 501 Goto.setTarget(s, (BranchOperand) target.copy()); 502 } 503 } else if (TableSwitch.conforms(s)) { 504 foundGoto = true; 505 if (TableSwitch.getDefault(s).similar(outTarget)) { 506 TableSwitch.setDefault(s, (BranchOperand) target.copy()); 507 } 508 for (int i = 0; i < TableSwitch.getNumberOfTargets(s); i++) { 509 if (TableSwitch.getTarget(s, i).similar(outTarget)) { 510 TableSwitch.setTarget(s, i, (BranchOperand) target.copy()); 511 } 512 } 513 } else if (LowTableSwitch.conforms(s)) { 514 foundGoto = true; 515 for (int i = 0; i < LowTableSwitch.getNumberOfTargets(s); i++) { 516 if (LowTableSwitch.getTarget(s, i).similar(outTarget)) { 517 LowTableSwitch.setTarget(s, i, (BranchOperand) target.copy()); 518 } 519 } 520 } else if (LookupSwitch.conforms(s)) { 521 foundGoto = true; 522 if (LookupSwitch.getDefault(s).similar(outTarget)) { 523 LookupSwitch.setDefault(s, (BranchOperand) target.copy()); 524 } 525 for (int i = 0; i < LookupSwitch.getNumberOfTargets(s); i++) { 526 if (LookupSwitch.getTarget(s, i).similar(outTarget)) { 527 LookupSwitch.setTarget(s, i, (BranchOperand) target.copy()); 528 } 529 } 530 } else { 531 // done processing all branches 532 break; 533 } 534 } 535 536 // 4. Add a goto bb->out 537 Instruction s = Goto.create(GOTO, out.makeJumpTarget()); 538 bb.appendInstruction(s); 539 // add goto in->next 540 // if out was not the fallthrough, add a GOTO to preserve this 541 // control flow 542 if (out != next) { 543 // if there's already a GOTO, there's no fall through 544 if (!foundGoto) { 545 /* 546 * TODO: come up with a better fix (?). 547 * 548 * This is a fix to a particular problem in dacapo xalan. 549 * 550 * We have a loop inside an exception handler, and the exception handler 551 * is empty. The loop termination condition simply falls through the 552 * exception handler to the next block. This works fine until LeaveSSA, 553 * when we split the final block and insert a GOTO to the exception handler 554 * block. When we reassemble the IR afterwards, kaboom. 555 * 556 * I would have though it better not to fall through empty exception handlers 557 * at all, and explicitly GOTO past them from the get go. RJG 4/2/7 558 */ 559 BasicBlock jumpTarget = next; 560 while (jumpTarget.isEmpty() && jumpTarget.isExceptionHandlerBasicBlock()) { 561 jumpTarget = jumpTarget.nextBasicBlockInCodeOrder(); 562 } 563 s = Goto.create(GOTO, jumpTarget.makeJumpTarget()); 564 in.appendInstruction(s); 565 } 566 } 567 568 // 5. Update the CFG 569 in.recomputeNormalOut(ir); 570 bb.recomputeNormalOut(ir); 571 572 return bb; 573 } 574 575 /** 576 * Is the operand u, which is a use in instruction s, also a def 577 * in instruction s? That is, is this operand defined as a DU operand 578 * in InstructionFormatList.dat. 579 * <p> 580 * TODO!!: This implementation is slow. Think about adding 581 * some IR support for this functionality; possibly add methods like 582 * enumeratePureDefs(), enumerateImpureUses(), etc ..., and restructure 583 * the caller to avoid having to call this function. Not going 584 * to put effort into this now, as the whole scratch register 585 * architecture has a questionable future. 586 */ 587 public static boolean useDoublesAsDef(Operand u, Instruction s) { 588 for (Enumeration<Operand> d = s.getDefs(); d.hasMoreElements();) { 589 Operand def = d.nextElement(); 590 if (def != null) { 591 if (def == u) return true; 592 } 593 } 594 return false; 595 } 596 597 /** 598 * Is the operand d, which is a def in instruction s, also a def 599 * in instruction s? That is, is this operand defined as a DU operand 600 * in InstructionFormatList.dat. 601 * <p> 602 * TODO!!: This implementation is slow. Think about adding 603 * some IR support for this functionality; possibly add methods like 604 * enumeratePureDefs(), enumerateImpureUses(), etc ..., and restructure 605 * the caller to avoid having to call this function. Not going 606 * to put effort into this now, as the whole scratch register 607 * architecture has a questionable future. 608 */ 609 public static boolean defDoublesAsUse(Operand d, Instruction s) { 610 for (Enumeration<Operand> u = s.getUses(); u.hasMoreElements();) { 611 Operand use = u.nextElement(); 612 if (use != null) { 613 if (use.similar(d)) return true; 614 } 615 } 616 return false; 617 } 618 619 /** 620 * Does instruction s define register r? 621 */ 622 public static boolean definedIn(Register r, Instruction s) { 623 for (Enumeration<Operand> e = s.getDefs(); e.hasMoreElements();) { 624 Operand op = e.nextElement(); 625 if (op != null && op.isRegister()) { 626 if (op.asRegister().getRegister().number == r.number) { 627 return true; 628 } 629 } 630 } 631 return false; 632 } 633 634 /** 635 * Does instruction s use register r? 636 */ 637 public static boolean usedIn(Register r, Instruction s) { 638 for (Enumeration<Operand> e = s.getUses(); e.hasMoreElements();) { 639 Operand op = e.nextElement(); 640 if (op != null && op.isRegister()) { 641 if (op.asRegister().getRegister().number == r.number) { 642 return true; 643 } 644 } 645 } 646 return false; 647 } 648 649 /** 650 * Mark the parameter as nonGC and nonPEI and return it. 651 * To be used in passthrough expressions like 652 * <pre> 653 * instr.insertBack(notPEIGC(Load.create(...))); 654 * </pre> 655 * 656 * @param instr the given instruction 657 * @return the given instruction 658 */ 659 public static Instruction nonPEIGC(Instruction instr) { 660 instr.markAsNonPEINonGCPoint(); 661 return instr; 662 } 663 664 /** 665 * Might this instruction be a load from a field that is declared 666 * to be volatile? 667 * 668 * @param s the insruction to check 669 * @return <code>true</code> if the instruction might be a load 670 * from a volatile field or <code>false</code> if it 671 * cannot be a load from a volatile field 672 */ 673 public static boolean mayBeVolatileFieldLoad(Instruction s) { 674 return s.mayBeVolatileFieldLoad(); 675 } 676 }