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 (InstructionEnumeration e = in.reverseRealInstrEnumerator(); e.hasMoreElements();) {
482 Instruction s = e.next();
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 *
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 *
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 }