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.hir2lir;
014
015import static org.jikesrvm.compilers.opt.driver.OptConstants.RUNTIME_SERVICES_BCI;
016import static org.jikesrvm.compilers.opt.ir.Operators.ARRAYLENGTH;
017import static org.jikesrvm.compilers.opt.ir.Operators.BOUNDS_CHECK_opcode;
018import static org.jikesrvm.compilers.opt.ir.Operators.BYTE_ALOAD_opcode;
019import static org.jikesrvm.compilers.opt.ir.Operators.BYTE_ASTORE_opcode;
020import static org.jikesrvm.compilers.opt.ir.Operators.BYTE_LOAD;
021import static org.jikesrvm.compilers.opt.ir.Operators.BYTE_STORE;
022import static org.jikesrvm.compilers.opt.ir.Operators.CALL;
023import static org.jikesrvm.compilers.opt.ir.Operators.CALL_opcode;
024import static org.jikesrvm.compilers.opt.ir.Operators.CHECKCAST_NOTNULL_opcode;
025import static org.jikesrvm.compilers.opt.ir.Operators.CHECKCAST_UNRESOLVED_opcode;
026import static org.jikesrvm.compilers.opt.ir.Operators.CHECKCAST_opcode;
027import static org.jikesrvm.compilers.opt.ir.Operators.DOUBLE_ALOAD_opcode;
028import static org.jikesrvm.compilers.opt.ir.Operators.DOUBLE_ASTORE_opcode;
029import static org.jikesrvm.compilers.opt.ir.Operators.DOUBLE_LOAD;
030import static org.jikesrvm.compilers.opt.ir.Operators.DOUBLE_STORE;
031import static org.jikesrvm.compilers.opt.ir.Operators.FLOAT_ALOAD_opcode;
032import static org.jikesrvm.compilers.opt.ir.Operators.FLOAT_ASTORE_opcode;
033import static org.jikesrvm.compilers.opt.ir.Operators.FLOAT_LOAD;
034import static org.jikesrvm.compilers.opt.ir.Operators.FLOAT_STORE;
035import static org.jikesrvm.compilers.opt.ir.Operators.GETFIELD_opcode;
036import static org.jikesrvm.compilers.opt.ir.Operators.GETSTATIC_opcode;
037import static org.jikesrvm.compilers.opt.ir.Operators.GET_CLASS_TIB;
038import static org.jikesrvm.compilers.opt.ir.Operators.GET_OBJ_TIB;
039import static org.jikesrvm.compilers.opt.ir.Operators.GOTO;
040import static org.jikesrvm.compilers.opt.ir.Operators.IG_CLASS_TEST_opcode;
041import static org.jikesrvm.compilers.opt.ir.Operators.IG_METHOD_TEST_opcode;
042import static org.jikesrvm.compilers.opt.ir.Operators.INSTANCEOF_NOTNULL_opcode;
043import static org.jikesrvm.compilers.opt.ir.Operators.INSTANCEOF_UNRESOLVED_opcode;
044import static org.jikesrvm.compilers.opt.ir.Operators.INSTANCEOF_opcode;
045import static org.jikesrvm.compilers.opt.ir.Operators.INT_2ADDRSigExt;
046import static org.jikesrvm.compilers.opt.ir.Operators.INT_2ADDRZerExt;
047import static org.jikesrvm.compilers.opt.ir.Operators.INT_ADD;
048import static org.jikesrvm.compilers.opt.ir.Operators.INT_ALOAD_opcode;
049import static org.jikesrvm.compilers.opt.ir.Operators.INT_ASTORE_opcode;
050import static org.jikesrvm.compilers.opt.ir.Operators.INT_IFCMP;
051import static org.jikesrvm.compilers.opt.ir.Operators.INT_IFCMP2;
052import static org.jikesrvm.compilers.opt.ir.Operators.INT_LOAD;
053import static org.jikesrvm.compilers.opt.ir.Operators.INT_SHL;
054import static org.jikesrvm.compilers.opt.ir.Operators.INT_STORE;
055import static org.jikesrvm.compilers.opt.ir.Operators.INT_ZERO_CHECK_opcode;
056import static org.jikesrvm.compilers.opt.ir.Operators.LONG_ALOAD_opcode;
057import static org.jikesrvm.compilers.opt.ir.Operators.LONG_ASTORE_opcode;
058import static org.jikesrvm.compilers.opt.ir.Operators.LONG_LOAD;
059import static org.jikesrvm.compilers.opt.ir.Operators.LONG_STORE;
060import static org.jikesrvm.compilers.opt.ir.Operators.LONG_ZERO_CHECK_opcode;
061import static org.jikesrvm.compilers.opt.ir.Operators.LOOKUPSWITCH;
062import static org.jikesrvm.compilers.opt.ir.Operators.LOOKUPSWITCH_opcode;
063import static org.jikesrvm.compilers.opt.ir.Operators.LOWTABLESWITCH;
064import static org.jikesrvm.compilers.opt.ir.Operators.MUST_IMPLEMENT_INTERFACE_opcode;
065import static org.jikesrvm.compilers.opt.ir.Operators.OBJARRAY_STORE_CHECK_NOTNULL_opcode;
066import static org.jikesrvm.compilers.opt.ir.Operators.OBJARRAY_STORE_CHECK_opcode;
067import static org.jikesrvm.compilers.opt.ir.Operators.PUTFIELD_opcode;
068import static org.jikesrvm.compilers.opt.ir.Operators.PUTSTATIC_opcode;
069import static org.jikesrvm.compilers.opt.ir.Operators.REF_ALOAD_opcode;
070import static org.jikesrvm.compilers.opt.ir.Operators.REF_ASTORE_opcode;
071import static org.jikesrvm.compilers.opt.ir.Operators.REF_IFCMP;
072import static org.jikesrvm.compilers.opt.ir.Operators.REF_LOAD;
073import static org.jikesrvm.compilers.opt.ir.Operators.REF_STORE;
074import static org.jikesrvm.compilers.opt.ir.Operators.RESOLVE;
075import static org.jikesrvm.compilers.opt.ir.Operators.RESOLVE_MEMBER_opcode;
076import static org.jikesrvm.compilers.opt.ir.Operators.SHORT_ALOAD_opcode;
077import static org.jikesrvm.compilers.opt.ir.Operators.SHORT_ASTORE_opcode;
078import static org.jikesrvm.compilers.opt.ir.Operators.SHORT_LOAD;
079import static org.jikesrvm.compilers.opt.ir.Operators.SHORT_STORE;
080import static org.jikesrvm.compilers.opt.ir.Operators.SYSCALL_opcode;
081import static org.jikesrvm.compilers.opt.ir.Operators.TABLESWITCH_opcode;
082import static org.jikesrvm.compilers.opt.ir.Operators.TRAP_IF;
083import static org.jikesrvm.compilers.opt.ir.Operators.UBYTE_ALOAD_opcode;
084import static org.jikesrvm.compilers.opt.ir.Operators.UBYTE_LOAD;
085import static org.jikesrvm.compilers.opt.ir.Operators.USHORT_ALOAD_opcode;
086import static org.jikesrvm.compilers.opt.ir.Operators.USHORT_LOAD;
087import static org.jikesrvm.mm.mminterface.MemoryManagerConstants.MOVES_TIBS;
088import static org.jikesrvm.objectmodel.TIBLayoutConstants.NEEDS_DYNAMIC_LINK;
089import static org.jikesrvm.objectmodel.TIBLayoutConstants.TIB_INTERFACE_DISPATCH_TABLE_INDEX;
090import static org.jikesrvm.runtime.JavaSizeConstants.LOG_BYTES_IN_INT;
091import static org.jikesrvm.runtime.UnboxedSizeConstants.LOG_BYTES_IN_ADDRESS;
092
093import org.jikesrvm.VM;
094import org.jikesrvm.adaptive.AosEntrypoints;
095import org.jikesrvm.classloader.InterfaceInvocation;
096import org.jikesrvm.classloader.InterfaceMethodSignature;
097import org.jikesrvm.classloader.RVMClass;
098import org.jikesrvm.classloader.RVMField;
099import org.jikesrvm.classloader.RVMMethod;
100import org.jikesrvm.classloader.RVMType;
101import org.jikesrvm.classloader.TypeReference;
102import org.jikesrvm.compilers.opt.OptOptions;
103import org.jikesrvm.compilers.opt.controlflow.BranchOptimizations;
104import org.jikesrvm.compilers.opt.ir.ALoad;
105import org.jikesrvm.compilers.opt.ir.AStore;
106import org.jikesrvm.compilers.opt.ir.BasicBlock;
107import org.jikesrvm.compilers.opt.ir.Binary;
108import org.jikesrvm.compilers.opt.ir.BoundsCheck;
109import org.jikesrvm.compilers.opt.ir.CacheOp;
110import org.jikesrvm.compilers.opt.ir.Call;
111import org.jikesrvm.compilers.opt.ir.GetField;
112import org.jikesrvm.compilers.opt.ir.GetStatic;
113import org.jikesrvm.compilers.opt.ir.Goto;
114import org.jikesrvm.compilers.opt.ir.GuardedUnary;
115import org.jikesrvm.compilers.opt.ir.IR;
116import org.jikesrvm.compilers.opt.ir.IRTools;
117import org.jikesrvm.compilers.opt.ir.IfCmp;
118import org.jikesrvm.compilers.opt.ir.IfCmp2;
119import org.jikesrvm.compilers.opt.ir.InlineGuard;
120import org.jikesrvm.compilers.opt.ir.Instruction;
121import org.jikesrvm.compilers.opt.ir.Load;
122import org.jikesrvm.compilers.opt.ir.LookupSwitch;
123import org.jikesrvm.compilers.opt.ir.LowTableSwitch;
124import org.jikesrvm.compilers.opt.ir.Operator;
125import org.jikesrvm.compilers.opt.ir.PutField;
126import org.jikesrvm.compilers.opt.ir.PutStatic;
127import org.jikesrvm.compilers.opt.ir.Store;
128import org.jikesrvm.compilers.opt.ir.TableSwitch;
129import org.jikesrvm.compilers.opt.ir.TrapIf;
130import org.jikesrvm.compilers.opt.ir.Unary;
131import org.jikesrvm.compilers.opt.ir.ZeroCheck;
132import org.jikesrvm.compilers.opt.ir.operand.AddressConstantOperand;
133import org.jikesrvm.compilers.opt.ir.operand.BranchOperand;
134import org.jikesrvm.compilers.opt.ir.operand.BranchProfileOperand;
135import org.jikesrvm.compilers.opt.ir.operand.ConditionOperand;
136import org.jikesrvm.compilers.opt.ir.operand.IntConstantOperand;
137import org.jikesrvm.compilers.opt.ir.operand.LocationOperand;
138import org.jikesrvm.compilers.opt.ir.operand.MethodOperand;
139import org.jikesrvm.compilers.opt.ir.operand.Operand;
140import org.jikesrvm.compilers.opt.ir.operand.RegisterOperand;
141import org.jikesrvm.compilers.opt.ir.operand.TIBConstantOperand;
142import org.jikesrvm.compilers.opt.ir.operand.TrapCodeOperand;
143import org.jikesrvm.compilers.opt.ir.operand.TypeOperand;
144import org.jikesrvm.compilers.opt.specialization.SpecializedMethod;
145import org.jikesrvm.runtime.Entrypoints;
146import org.jikesrvm.runtime.Magic;
147import org.vmmagic.unboxed.Address;
148import org.vmmagic.unboxed.Offset;
149
150/**
151 * Converts all remaining instructions with HIR-only operators into
152 * an equivalent sequence of LIR operators.
153 */
154public abstract class ConvertToLowLevelIR extends IRTools {
155
156  /**
157   * We have slightly different ideas of what the LIR should look like
158   * for IA32 and PowerPC.  The main difference is that for IA32
159   * instead of bending over backwards in BURS to rediscover array
160   * loads, (where we can use base + index*scale addressing modes),
161   * we'll leave array loads in the LIR.
162   */
163  public static final boolean LOWER_ARRAY_ACCESS = VM.BuildForPowerPC;
164
165  /**
166   * Converts the given HIR to LIR.
167   *
168   * @param ir IR to convert
169   * @param options the options for the conversion
170   */
171  static void convert(IR ir, OptOptions options) {
172    boolean didArrayStoreCheck = false;
173    for (Instruction s = ir.firstInstructionInCodeOrder(); s != null; s = s.nextInstructionInCodeOrder()) {
174
175      switch (s.getOpcode()) {
176        case GETSTATIC_opcode: {
177          LocationOperand loc = GetStatic.getClearLocation(s);
178          RegisterOperand result = GetStatic.getClearResult(s);
179          Operand address = ir.regpool.makeJTOCOp();
180          Operand offset = GetStatic.getClearOffset(s);
181          Load.mutate(s, IRTools.getLoadOp(loc.getFieldRef(), true), result, address, offset, loc);
182        }
183        break;
184
185        case PUTSTATIC_opcode: {
186          LocationOperand loc = PutStatic.getClearLocation(s);
187          Operand value = PutStatic.getClearValue(s);
188          Operand address = ir.regpool.makeJTOCOp();
189          Operand offset = PutStatic.getClearOffset(s);
190          Store.mutate(s, IRTools.getStoreOp(loc.getFieldRef(), true), value, address, offset, loc);
191        }
192        break;
193
194        case PUTFIELD_opcode: {
195          LocationOperand loc = PutField.getClearLocation(s);
196          Operand value = PutField.getClearValue(s);
197          Operand address = PutField.getClearRef(s);
198          Operand offset = PutField.getClearOffset(s);
199          Store.mutate(s,
200                       IRTools.getStoreOp(loc.getFieldRef(), false),
201                       value,
202                       address,
203                       offset,
204                       loc,
205                       PutField.getClearGuard(s));
206        }
207        break;
208
209        case GETFIELD_opcode: {
210          LocationOperand loc = GetField.getClearLocation(s);
211          RegisterOperand result = GetField.getClearResult(s);
212          Operand address = GetField.getClearRef(s);
213          Operand offset = GetField.getClearOffset(s);
214          Load.mutate(s,
215                      IRTools.getLoadOp(loc.getFieldRef(), false),
216                      result,
217                      address,
218                      offset,
219                      loc,
220                      GetField.getClearGuard(s));
221        }
222        break;
223
224        case INT_ALOAD_opcode:
225          doArrayLoad(s, ir, INT_LOAD, 2);
226          break;
227
228        case LONG_ALOAD_opcode:
229          doArrayLoad(s, ir, LONG_LOAD, 3);
230          break;
231
232        case FLOAT_ALOAD_opcode:
233          doArrayLoad(s, ir, FLOAT_LOAD, 2);
234          break;
235
236        case DOUBLE_ALOAD_opcode:
237          doArrayLoad(s, ir, DOUBLE_LOAD, 3);
238          break;
239
240        case REF_ALOAD_opcode:
241          doArrayLoad(s, ir, REF_LOAD, LOG_BYTES_IN_ADDRESS);
242          break;
243
244        case BYTE_ALOAD_opcode:
245          doArrayLoad(s, ir, BYTE_LOAD, 0);
246          break;
247
248        case UBYTE_ALOAD_opcode:
249          doArrayLoad(s, ir, UBYTE_LOAD, 0);
250          break;
251
252        case USHORT_ALOAD_opcode:
253          doArrayLoad(s, ir, USHORT_LOAD, 1);
254          break;
255
256        case SHORT_ALOAD_opcode:
257          doArrayLoad(s, ir, SHORT_LOAD, 1);
258          break;
259
260        case INT_ASTORE_opcode:
261          doArrayStore(s, ir, INT_STORE, 2);
262          break;
263
264        case LONG_ASTORE_opcode:
265          doArrayStore(s, ir, LONG_STORE, 3);
266          break;
267
268        case FLOAT_ASTORE_opcode:
269          doArrayStore(s, ir, FLOAT_STORE, 2);
270          break;
271
272        case DOUBLE_ASTORE_opcode:
273          doArrayStore(s, ir, DOUBLE_STORE, 3);
274          break;
275
276        case REF_ASTORE_opcode:
277          doArrayStore(s, ir, REF_STORE, LOG_BYTES_IN_ADDRESS);
278          break;
279
280        case BYTE_ASTORE_opcode:
281          doArrayStore(s, ir, BYTE_STORE, 0);
282          break;
283
284        case SHORT_ASTORE_opcode:
285          doArrayStore(s, ir, SHORT_STORE, 1);
286          break;
287
288        case CALL_opcode:
289          s = callHelper(s, ir);
290          break;
291
292        case SYSCALL_opcode:
293          // If the SYSCALL is using a symbolic address, convert that to
294          // a sequence of loads off the BootRecord to find the appropriate field.
295          if (Call.getMethod(s) != null) {
296            expandSysCallTarget(s, ir);
297          }
298          break;
299
300        case TABLESWITCH_opcode:
301          s = tableswitch(s, ir);
302          break;
303
304        case LOOKUPSWITCH_opcode:
305          s = lookup(s, ir);
306          break;
307
308        case OBJARRAY_STORE_CHECK_opcode:
309          s = DynamicTypeCheckExpansion.arrayStoreCheck(s, ir, true);
310          didArrayStoreCheck = true;
311          break;
312
313        case OBJARRAY_STORE_CHECK_NOTNULL_opcode:
314          s = DynamicTypeCheckExpansion.arrayStoreCheck(s, ir, false);
315          didArrayStoreCheck = true;
316          break;
317
318        case CHECKCAST_opcode:
319        case CHECKCAST_UNRESOLVED_opcode:
320          s = DynamicTypeCheckExpansion.checkcast(s, ir);
321          break;
322
323        case CHECKCAST_NOTNULL_opcode:
324          s = DynamicTypeCheckExpansion.checkcastNotNull(s, ir);
325          break;
326
327        case MUST_IMPLEMENT_INTERFACE_opcode:
328          s = DynamicTypeCheckExpansion.mustImplementInterface(s, ir);
329          break;
330
331        case IG_CLASS_TEST_opcode:
332          IfCmp.mutate(s,
333                       REF_IFCMP,
334                       ir.regpool.makeTempValidation(),
335                       getTIB(s, ir, InlineGuard.getClearValue(s), InlineGuard.getClearGuard(s)),
336                       getTIB(s, ir, InlineGuard.getGoal(s).asType()),
337                       ConditionOperand.NOT_EQUAL(),
338                       InlineGuard.getClearTarget(s),
339                       InlineGuard.getClearBranchProfile(s));
340          break;
341
342        case IG_METHOD_TEST_opcode: {
343          MethodOperand methOp = InlineGuard.getClearGoal(s).asMethod();
344          Operand t1 = getTIB(s, ir, InlineGuard.getClearValue(s), InlineGuard.getClearGuard(s));
345          Operand t2 = getTIB(s, ir, methOp.getTarget().getDeclaringClass());
346          IfCmp.mutate(s,
347                       REF_IFCMP,
348                       ir.regpool.makeTempValidation(),
349                       getInstanceMethod(s, ir, t1, methOp.getTarget()),
350                       getInstanceMethod(s, ir, t2, methOp.getTarget()),
351                       ConditionOperand.NOT_EQUAL(),
352                       InlineGuard.getClearTarget(s),
353                       InlineGuard.getClearBranchProfile(s));
354          break;
355        }
356
357        case INSTANCEOF_opcode:
358        case INSTANCEOF_UNRESOLVED_opcode:
359          s = DynamicTypeCheckExpansion.instanceOf(s, ir);
360          break;
361
362        case INSTANCEOF_NOTNULL_opcode:
363          s = DynamicTypeCheckExpansion.instanceOfNotNull(s, ir);
364          break;
365
366        case INT_ZERO_CHECK_opcode: {
367          TrapIf.mutate(s,
368                        TRAP_IF,
369                        ZeroCheck.getClearGuardResult(s),
370                        ZeroCheck.getClearValue(s),
371                        IC(0),
372                        ConditionOperand.EQUAL(),
373                        TrapCodeOperand.DivByZero());
374        }
375        break;
376
377        case LONG_ZERO_CHECK_opcode: {
378          TrapIf.mutate(s,
379                        TRAP_IF,
380                        ZeroCheck.getClearGuardResult(s),
381                        ZeroCheck.getClearValue(s),
382                        LC(0),
383                        ConditionOperand.EQUAL(),
384                        TrapCodeOperand.DivByZero());
385        }
386        break;
387
388        case BOUNDS_CHECK_opcode: {
389          // get array_length from array_ref
390          RegisterOperand array_length =
391              InsertGuardedUnary(s,
392                                 ir,
393                                 ARRAYLENGTH,
394                                 TypeReference.Int,
395                                 BoundsCheck.getClearRef(s),
396                                 BoundsCheck.getClearGuard(s));
397          //  In UN-signed comparison, a negative index will look like a very
398          //  large positive number, greater than array length.
399          //  Thus length LLT index is false iff 0 <= index <= length
400          TrapIf.mutate(s,
401                        TRAP_IF,
402                        BoundsCheck.getClearGuardResult(s),
403                        array_length.copyD2U(),
404                        BoundsCheck.getClearIndex(s),
405                        ConditionOperand.LOWER_EQUAL(),
406                        TrapCodeOperand.ArrayBounds());
407        }
408        break;
409
410        case RESOLVE_MEMBER_opcode:
411          s = resolveMember(s, ir);
412          break;
413
414        default:
415          break;
416      }
417    }
418    // Eliminate possible redundant trap block from array store checks
419    if (didArrayStoreCheck) {
420      branchOpts.perform(ir, true);
421    }
422  }
423
424  private static BranchOptimizations branchOpts = new BranchOptimizations(-1, true, true);
425
426  /**
427   * Expand a tableswitch.
428   * @param s the instruction to expand
429   * @param ir the containing IR
430   * @return the last Instruction in the generated LIR sequence.
431   */
432  static Instruction tableswitch(Instruction s, IR ir) {
433
434    Instruction s2;
435    int lowLimit = TableSwitch.getLow(s).value;
436    int highLimit = TableSwitch.getHigh(s).value;
437    int number = highLimit - lowLimit + 1;
438    if (VM.VerifyAssertions) {
439      VM._assert(number > 0);    // also checks that there are < 2^31 targets
440    }
441    Operand val = TableSwitch.getClearValue(s);
442    BranchOperand defaultLabel = TableSwitch.getClearDefault(s);
443    if (number < ir.options.CONTROL_TABLESWITCH_CUTOFF) { // convert into a lookupswitch
444      Instruction l =
445          LookupSwitch.create(LOOKUPSWITCH,
446                              val,
447                              null,
448                              null,
449                              defaultLabel,
450                              TableSwitch.getClearDefaultBranchProfile(s),
451                              number * 3);
452      for (int i = 0; i < number; i++) {
453        LookupSwitch.setMatch(l, i, IC(lowLimit + i));
454        LookupSwitch.setTarget(l, i, TableSwitch.getClearTarget(s, i));
455        LookupSwitch.setBranchProfile(l, i, TableSwitch.getClearBranchProfile(s, i));
456      }
457      s.insertAfter(CPOS(s, l));
458      return s.remove();
459    }
460    RegisterOperand reg = val.asRegister();
461    BasicBlock BB1 = s.getBasicBlock();
462    BasicBlock BB2 = BB1.splitNodeAt(s, ir);
463    BasicBlock defaultBB = defaultLabel.target.getBasicBlock();
464
465    /******* First basic block */
466    RegisterOperand t;
467    if (lowLimit != 0) {
468      t = insertBinary(s, ir, INT_ADD, TypeReference.Int, reg, IC(-lowLimit));
469    } else {
470      t = reg.copyU2U();
471    }
472    BranchProfileOperand defaultProb = TableSwitch.getClearDefaultBranchProfile(s);
473    s.replace(CPOS(s, IfCmp.create(INT_IFCMP,
474                        ir.regpool.makeTempValidation(),
475                        t,
476                        IC(highLimit - lowLimit),
477                        ConditionOperand.HIGHER(),
478                        defaultLabel,
479                        defaultProb)));
480    // Reweight branches to account for the default branch going. If
481    // the default probability was ALWAYS then when we recompute the
482    // weight to be a proportion of the total number of branches.
483    final boolean defaultIsAlways = defaultProb.takenProbability >= 1f;
484    final float weight = defaultIsAlways ? 1f / number : 1f / (1f - defaultProb.takenProbability);
485
486    /********** second Basic Block ******/
487    s2 = CPOS(s, LowTableSwitch.create(LOWTABLESWITCH, t.copyRO(), number * 2));
488    boolean containsDefault = false;
489    for (int i = 0; i < number; i++) {
490      BranchOperand b = TableSwitch.getClearTarget(s, i);
491      LowTableSwitch.setTarget(s2, i, b);
492      BranchProfileOperand bp = TableSwitch.getClearBranchProfile(s, i);
493      if (defaultIsAlways) {
494        bp.takenProbability = weight;
495      } else {
496        bp.takenProbability *= weight;
497      }
498      LowTableSwitch.setBranchProfile(s2, i, bp);
499      if (b.target == defaultLabel.target) {
500        containsDefault = true;
501      }
502    }
503    // Fixup the CFG and code order.
504    BB1.insertOut(BB2);
505    BB1.insertOut(defaultBB);
506    ir.cfg.linkInCodeOrder(BB1, BB2);
507    if (!containsDefault) {
508      BB2.deleteOut(defaultBB);
509    }
510    // Simplify a fringe case...
511    // if all targets of the LOWTABLESWITCH are the same,
512    // then just use a GOTO instead of the LOWTABLESWITCH.
513    // This actually happens (very occasionally), and is easy to test for.
514    if (BB2.getNumberOfNormalOut() == 1) {
515      BB2.appendInstruction(CPOS(s, Goto.create(GOTO, LowTableSwitch.getTarget(s2, 0))));
516    } else {
517      BB2.appendInstruction(s2);
518    }
519    // continue at next BB
520    s = BB2.lastInstruction();
521
522    return s;
523  }
524
525  /**
526   * Expand a lookupswitch.
527   * @param switchInstr  The instruction to expand
528   * @param ir           The containing IR
529   * @return the next {@link Instruction} after the generated LIR sequence.
530   */
531  static Instruction lookup(Instruction switchInstr, IR ir) {
532    Instruction bbend = switchInstr.nextInstructionInCodeOrder();
533    BasicBlock thisBB = bbend.getBasicBlock();
534    BasicBlock nextBB = thisBB.nextBasicBlockInCodeOrder();
535    // Blow away the old Normal ControlFlowGraph edges to prepare for new links
536    thisBB.deleteNormalOut();
537    switchInstr.remove();
538    BranchOperand defTarget = LookupSwitch.getClearDefault(switchInstr);
539    BasicBlock defaultBB = defTarget.target.getBasicBlock();
540    int high = LookupSwitch.getNumberOfTargets(switchInstr) - 1;
541    if (high < 0) {
542      // no cases in switch; just jump to defaultBB
543      thisBB.appendInstruction(Goto.create(GOTO, defTarget));
544      thisBB.insertOut(defaultBB);
545    } else {
546      Operand match = LookupSwitch.getValue(switchInstr);
547      if (match.isConstant()) {
548        // switch on a constant
549        int value = match.asIntConstant().value;
550        int numMatches = LookupSwitch.getNumberOfMatches(switchInstr);
551        BranchOperand target = LookupSwitch.getDefault(switchInstr);
552        for (int i = 0; i < numMatches; i++) {
553          if (value == LookupSwitch.getMatch(switchInstr, i).value) {
554            target = LookupSwitch.getTarget(switchInstr, i);
555            break;
556          }
557        }
558        thisBB.appendInstruction(Goto.create(GOTO, target));
559        thisBB.insertOut(target.target.getBasicBlock());
560      } else {
561        RegisterOperand reg = match.asRegister();
562
563        // If you're not already at the end of the code order
564        if (nextBB != null) {
565          ir.cfg.breakCodeOrder(thisBB, nextBB);
566        }
567        // generate the binary search tree into thisBB
568        BasicBlock lastNewBB =
569            _lookupswitchHelper(switchInstr, reg, defaultBB, ir, thisBB, 0, high, Integer.MIN_VALUE, Integer.MAX_VALUE);
570        if (nextBB != null) {
571          ir.cfg.linkInCodeOrder(lastNewBB, nextBB);
572        }
573      }
574    }
575
576    // skip all the instrs just inserted by _lookupswitchHelper
577    if (nextBB != null) {
578      return nextBB.firstInstruction();
579    } else {
580      return thisBB.lastInstruction();
581    }
582  }
583
584  /**
585   * Helper function to generate the binary search tree for
586   * a lookupswitch bytecode
587   *
588   * @param switchInstr the lookupswitch instruction
589   * @param defaultBB the basic block of the default case
590   * @param ir the ir object
591   * @param curBlock the basic block to insert instructions into
592   * @param reg the RegisterOperand that contains the valued being switched on
593   * @param low the low index of cases (operands of switchInstr)
594   * @param high the high index of cases (operands of switchInstr)
595   * @param min minimum for the current case
596   * @param max maximum for the current case
597   * @return the last basic block created
598   */
599  private static BasicBlock _lookupswitchHelper(Instruction switchInstr, RegisterOperand reg,
600                                                    BasicBlock defaultBB, IR ir, BasicBlock curBlock,
601                                                    int low, int high, int min, int max) {
602    if (VM.VerifyAssertions) {
603      VM._assert(low <= high, "broken control logic in _lookupswitchHelper");
604    }
605
606    int middle = (low + high) >> 1;             // find middle
607
608    // The following are used below to store the computed branch
609    // probabilities for the branches that are created to implement
610    // the binary search.  Used only if basic block frequencies available
611    float lessProb = 0.0f;
612    float greaterProb = 0.0f;
613    float equalProb = 0.0f;
614    float sum = 0.0f;
615
616    // Sum the probabilities for all targets < middle
617    for (int i = low; i < middle; i++) {
618      lessProb += LookupSwitch.getBranchProfile(switchInstr, i).takenProbability;
619    }
620
621    // Sum the probabilities for all targets > middle
622    for (int i = middle + 1; i <= high; i++) {
623      greaterProb += LookupSwitch.getBranchProfile(switchInstr, i).takenProbability;
624    }
625    equalProb = LookupSwitch.getBranchProfile(switchInstr, middle).takenProbability;
626
627    // The default case is a bit of a kludge.  We know the total
628    // probability of executing the default case, but we have no
629    // idea which paths are taken to get there.  For now, we'll
630    // assume that all paths that went to default were because the
631    // value was less than the smallest switch value.  This ensures
632    // that all basic block appearing in the switch will have the
633    // correct weights (but the blocks in the binary switch
634    // generated may not).
635    if (low == 0) {
636      lessProb += LookupSwitch.getDefaultBranchProfile(switchInstr).takenProbability;
637    }
638
639    // Now normalize them so they are relative to the sum of the
640    // branches being considered in this piece of the subtree
641    sum = lessProb + equalProb + greaterProb;
642    if (sum > 0) {  // check for divide by zero
643      lessProb /= sum;
644      equalProb /= sum;
645      greaterProb /= sum;
646    }
647
648    IntConstantOperand val = LookupSwitch.getClearMatch(switchInstr, middle);
649    int value = val.value;
650    BasicBlock greaterBlock = middle == high ? defaultBB : curBlock.createSubBlock(0, ir);
651    BasicBlock lesserBlock = low == middle ? defaultBB : curBlock.createSubBlock(0, ir);
652    // Generate this level of tests
653    BranchOperand branch = LookupSwitch.getClearTarget(switchInstr, middle);
654    BasicBlock branchBB = branch.target.getBasicBlock();
655    curBlock.insertOut(branchBB);
656    if (low != high) {
657      if (value == min) {
658        curBlock.appendInstruction(IfCmp.create(INT_IFCMP,
659            ir.regpool.makeTempValidation(),
660            reg.copy(),
661            val,
662            ConditionOperand.EQUAL(),
663            branchBB.makeJumpTarget(),
664            new BranchProfileOperand(equalProb)));
665      } else {
666
667        // To compute the probability of the second compare, the first
668        // probability must be removed since the second branch is
669        // considered only if the first fails.
670        float secondIfProb = 0.0f;
671        sum = equalProb + greaterProb;
672        if (sum > 0) {
673          // if divide by zero, leave as is
674          secondIfProb = equalProb / sum;
675        }
676
677        curBlock.appendInstruction(IfCmp2.create(INT_IFCMP2,
678            ir.regpool.makeTempValidation(),
679            reg.copy(),
680            val,
681            ConditionOperand.LESS(),
682            lesserBlock.makeJumpTarget(),
683            new BranchProfileOperand(lessProb),
684            ConditionOperand.EQUAL(),
685            branchBB.makeJumpTarget(),
686            new BranchProfileOperand(secondIfProb)));
687        curBlock.insertOut(lesserBlock);
688      }
689    } else {      // Base case: middle was the only case left to consider
690      if (min == max) {
691        curBlock.appendInstruction(Goto.create(GOTO, branch));
692        curBlock.insertOut(branchBB);
693      } else {
694        curBlock.appendInstruction(IfCmp.create(INT_IFCMP,
695            ir.regpool.makeTempValidation(),
696            reg.copy(),
697            val,
698            ConditionOperand.EQUAL(),
699            branchBB.makeJumpTarget(),
700            new BranchProfileOperand(equalProb)));
701        BasicBlock newBlock = curBlock.createSubBlock(0, ir);
702        curBlock.insertOut(newBlock);
703        ir.cfg.linkInCodeOrder(curBlock, newBlock);
704        curBlock = newBlock;
705        curBlock.appendInstruction(defaultBB.makeGOTO());
706        curBlock.insertOut(defaultBB);
707      }
708    }
709    // Generate sublevels as needed and splice together instr & bblist
710    if (middle < high) {
711      curBlock.insertOut(greaterBlock);
712      ir.cfg.linkInCodeOrder(curBlock, greaterBlock);
713      curBlock = _lookupswitchHelper(switchInstr, reg, defaultBB, ir, greaterBlock, middle + 1, high, value + 1, max);
714    }
715    if (low < middle) {
716      ir.cfg.linkInCodeOrder(curBlock, lesserBlock);
717      curBlock = _lookupswitchHelper(switchInstr, reg, defaultBB, ir, lesserBlock, low, middle - 1, min, value - 1);
718    }
719    return curBlock;
720  }
721
722  /**
723   * Expand an array load.
724   * @param s the instruction to expand
725   * @param ir the containing IR
726   * @param op the load operator to use
727   * @param logwidth the log base 2 of the element type's size
728   */
729  public static void doArrayLoad(Instruction s, IR ir, Operator op, int logwidth) {
730    if (LOWER_ARRAY_ACCESS) {
731      RegisterOperand result = ALoad.getClearResult(s);
732      Operand array = ALoad.getClearArray(s);
733      Operand index = ALoad.getClearIndex(s);
734      Operand offset;
735      LocationOperand loc = ALoad.getClearLocation(s);
736      if (index instanceof IntConstantOperand) {  // constant propagation
737        offset = AC(Address.fromIntZeroExtend(((IntConstantOperand) index).value << logwidth));
738      } else {
739        if (logwidth != 0) {
740          offset = insertBinary(s, ir, INT_SHL, TypeReference.Int, index, IC(logwidth));
741          offset = InsertUnary(s, ir, INT_2ADDRZerExt, TypeReference.Offset, offset.copy());
742        } else {
743          offset = InsertUnary(s, ir, INT_2ADDRZerExt, TypeReference.Offset, index);
744        }
745      }
746      Load.mutate(s, op, result, array, offset, loc, ALoad.getClearGuard(s));
747    }
748  }
749
750  /**
751   * Expand an array store.
752   * @param s the instruction to expand
753   * @param ir the containing IR
754   * @param op the store operator to use
755   * @param logwidth the log base 2 of the element type's size
756   */
757  public static void doArrayStore(Instruction s, IR ir, Operator op, int logwidth) {
758    if (LOWER_ARRAY_ACCESS) {
759      Operand value = AStore.getClearValue(s);
760      Operand array = AStore.getClearArray(s);
761      Operand index = AStore.getClearIndex(s);
762      Operand offset;
763      LocationOperand loc = AStore.getClearLocation(s);
764      if (index instanceof IntConstantOperand) { // constant propagation
765        offset = AC(Address.fromIntZeroExtend(((IntConstantOperand) index).value << logwidth));
766      } else {
767        if (logwidth != 0) {
768          offset = insertBinary(s, ir, INT_SHL, TypeReference.Int, index, IC(logwidth));
769          offset = InsertUnary(s, ir, INT_2ADDRZerExt, TypeReference.Offset, offset.copy());
770        } else {
771          offset = InsertUnary(s, ir, INT_2ADDRZerExt, TypeReference.Offset, index);
772        }
773      }
774      Store.mutate(s, op, value, array, offset, loc, AStore.getClearGuard(s));
775    }
776  }
777
778  /**
779   * Helper method for call expansion.
780   * @param v the call instruction
781   * @param ir the containing IR
782   * @return the last expanded instruction
783   */
784  static Instruction callHelper(Instruction v, IR ir) {
785    if (!Call.hasMethod(v)) {
786      if (VM.VerifyAssertions) VM._assert(Call.getAddress(v) instanceof RegisterOperand);
787      return v; // nothing to do....very low level call to address already in the register.
788    }
789
790    MethodOperand methOp = Call.getMethod(v);
791
792    // Handle recursive invocations.
793    if (methOp.hasPreciseTarget() && methOp.getTarget() == ir.method) {
794      Call.setAddress(v, new BranchOperand(ir.firstInstructionInCodeOrder()));
795      return v;
796    }
797
798    /* RRB 100500 */
799    // generate direct call to specialized method if the method operand
800    // has been marked as a specialized call.
801    if (VM.runningVM) {
802      SpecializedMethod spMethod = methOp.spMethod;
803      if (spMethod != null) {
804        int smid = spMethod.getSpecializedMethodIndex();
805        Call.setAddress(v, getSpecialMethod(v, ir, smid));
806        return v;
807      }
808    }
809
810    // Used mainly (only?) by OSR
811    if (methOp.hasDesignatedTarget()) {
812      Call.setAddress(v, InsertLoadOffsetJTOC(v, ir, REF_LOAD, TypeReference.CodeArray, methOp.jtocOffset));
813      return v;
814    }
815
816    if (methOp.isStatic()) {
817      if (VM.VerifyAssertions) VM._assert(Call.hasAddress(v));
818      Call.setAddress(v, InsertLoadOffsetJTOC(v, ir, REF_LOAD, TypeReference.CodeArray, Call.getClearAddress(v)));
819    } else if (methOp.isVirtual()) {
820      if (VM.VerifyAssertions) VM._assert(Call.hasAddress(v));
821      if (ir.options.H2L_CALL_VIA_JTOC && methOp.hasPreciseTarget()) {
822        // Call to precise type can go via JTOC
823        RVMMethod target = methOp.getTarget();
824        Call.setAddress(v,
825                        InsertLoadOffsetJTOC(v,
826                                             ir,
827                                             REF_LOAD,
828                                             TypeReference.CodeArray,
829                                             target.findOrCreateJtocOffset()));
830      } else {
831        Operand tib = getTIB(v, ir, Call.getParam(v, 0).copy(), Call.getGuard(v).copy());
832        Call.setAddress(v,
833                        InsertLoadOffset(v,
834                                         ir,
835                                         REF_LOAD,
836                                         TypeReference.CodeArray,
837                                         tib,
838                                         Call.getClearAddress(v),
839                                         null,
840                                         TG()));
841      }
842    } else if (methOp.isSpecial()) {
843      RVMMethod target = methOp.getTarget();
844      if (target == null || target.isObjectInitializer() || target.isStatic()) {
845        // target == null => we are calling an unresolved <init> method.
846        Call.setAddress(v, InsertLoadOffsetJTOC(v, ir, REF_LOAD, TypeReference.CodeArray, Call.getClearAddress(v)));
847      } else {
848        if (ir.options.H2L_CALL_VIA_JTOC) {
849          Call.setAddress(v,
850                          InsertLoadOffsetJTOC(v,
851                                               ir,
852                                               REF_LOAD,
853                                               TypeReference.CodeArray,
854                                               target.findOrCreateJtocOffset()));
855        } else {
856          // invoking a virtual method; do it via TIB of target's declaring class.
857          Operand tib = getTIB(v, ir, target.getDeclaringClass());
858          Call.setAddress(v,
859                          InsertLoadOffset(v,
860                                           ir,
861                                           REF_LOAD,
862                                           TypeReference.CodeArray,
863                                           tib,
864                                           Call.getClearAddress(v),
865                                           null,
866                                           TG()));
867        }
868      }
869    } else {
870      if (VM.VerifyAssertions) VM._assert(methOp.isInterface());
871      if (VM.VerifyAssertions) VM._assert(!Call.hasAddress(v));
872      if (VM.BuildForIMTInterfaceInvocation) {
873        // SEE ALSO: FinalMIRExpansion (for hidden parameter)
874        Operand RHStib = getTIB(v, ir, Call.getParam(v, 0).copy(), Call.getGuard(v).copy());
875        InterfaceMethodSignature sig = InterfaceMethodSignature.findOrCreate(methOp.getMemberRef());
876        Offset offset = sig.getIMTOffset();
877        RegisterOperand address = null;
878        RegisterOperand IMT =
879          InsertLoadOffset(v,
880                           ir,
881                           REF_LOAD,
882                           TypeReference.IMT,
883                           RHStib.copy(),
884                           Offset.fromIntZeroExtend(TIB_INTERFACE_DISPATCH_TABLE_INDEX << LOG_BYTES_IN_ADDRESS));
885        address = InsertLoadOffset(v, ir, REF_LOAD, TypeReference.CodeArray, IMT.copyD2U(), offset);
886
887        Call.setAddress(v, address);
888      } else {
889        int itableIndex = -1;
890        if (VM.BuildForITableInterfaceInvocation && methOp.hasTarget()) {
891          RVMClass I = methOp.getTarget().getDeclaringClass();
892          // search ITable variant
893          itableIndex =
894              InterfaceInvocation.getITableIndex(I,
895                                                    methOp.getMemberRef().getName(),
896                                                    methOp.getMemberRef().getDescriptor());
897        }
898        if (itableIndex == -1) {
899          // itable index is not known at compile-time.
900          // call "invokeinterface" to resolve the object and method id
901          // into a method address
902          RegisterOperand realAddrReg = ir.regpool.makeTemp(TypeReference.CodeArray);
903          RVMMethod target = Entrypoints.invokeInterfaceMethod;
904          Instruction vp =
905              Call.create2(CALL,
906                           realAddrReg,
907                           AC(target.getOffset()),
908                           MethodOperand.STATIC(target),
909                           Call.getParam(v, 0).asRegister().copyU2U(),
910                           IC(methOp.getMemberRef().getId()));
911          vp.position = v.position;
912          vp.bcIndex = RUNTIME_SERVICES_BCI;
913          v.insertBefore(vp);
914          callHelper(vp, ir);
915          Call.setAddress(v, realAddrReg.copyD2U());
916          return v;
917        } else {
918          // itable index is known at compile-time.
919          // call "findITable" to resolve object + interface id into
920          // itable address
921          RegisterOperand iTable = ir.regpool.makeTemp(TypeReference.ITable);
922          Operand RHStib = getTIB(v, ir, Call.getParam(v, 0).copy(), Call.getGuard(v).copy());
923          RVMMethod target = Entrypoints.findItableMethod;
924          Instruction fi =
925              Call.create2(CALL,
926                           iTable,
927                           AC(target.getOffset()),
928                           MethodOperand.STATIC(target),
929                           RHStib,
930                           IC(methOp.getTarget().getDeclaringClass().getInterfaceId()));
931          fi.position = v.position;
932          fi.bcIndex = RUNTIME_SERVICES_BCI;
933          v.insertBefore(fi);
934          callHelper(fi, ir);
935          RegisterOperand address =
936              InsertLoadOffset(v,
937                               ir,
938                               REF_LOAD,
939                               TypeReference.CodeArray,
940                               iTable.copyD2U(),
941                               Offset.fromIntZeroExtend(itableIndex << LOG_BYTES_IN_ADDRESS));
942          Call.setAddress(v, address);
943          return v;
944        }
945      }
946    }
947    return v;
948  }
949
950  /**
951   * Generate the code to resolve a member (field/method) reference.
952   * @param s the RESOLVE_MEMBER instruction to expand
953   * @param ir the containing ir object
954   * @return the last expanded instruction
955   */
956  private static Instruction resolveMember(Instruction s, IR ir) {
957    Operand memberOp = Unary.getClearVal(s);
958    RegisterOperand offset = Unary.getClearResult(s);
959    int dictId;
960    if (memberOp instanceof LocationOperand) {
961      dictId = ((LocationOperand) memberOp).getFieldRef().getId();
962    } else {
963      dictId = ((MethodOperand) memberOp).getMemberRef().getId();
964    }
965
966    BranchProfileOperand bp = BranchProfileOperand.never();
967    BasicBlock predBB = s.getBasicBlock();
968    BasicBlock succBB = predBB.splitNodeAt(s.prevInstructionInCodeOrder(), ir);
969    BasicBlock testBB = predBB.createSubBlock(s.bcIndex, ir, 1f - bp.takenProbability);
970    BasicBlock resolveBB = predBB.createSubBlock(s.bcIndex, ir, bp.takenProbability);
971    s.remove();
972
973    // Get the offset from the appropriate RVMClassLoader array
974    // and check to see if it is valid
975    RegisterOperand offsetTable = getStatic(testBB.lastInstruction(), ir, Entrypoints.memberOffsetsField);
976    testBB.appendInstruction(Load.create(INT_LOAD,
977                                         offset.copyRO(),
978                                         offsetTable,
979                                         AC(Offset.fromIntZeroExtend(dictId << LOG_BYTES_IN_INT)),
980                                         new LocationOperand(TypeReference.Int),
981                                         TG()));
982    testBB.appendInstruction(Unary.create(INT_2ADDRSigExt, offset, offset.copy()));
983    testBB.appendInstruction(IfCmp.create(REF_IFCMP,
984        ir.regpool.makeTempValidation(),
985        offset.copy(),
986        AC(Address.fromIntSignExtend(NEEDS_DYNAMIC_LINK)),
987        ConditionOperand.EQUAL(),
988        resolveBB.makeJumpTarget(),
989        bp));
990
991    // Handle the offset being invalid
992    resolveBB.appendInstruction(CacheOp.mutate(s, RESOLVE, memberOp));
993    resolveBB.appendInstruction(testBB.makeGOTO());
994
995    // Put together the CFG links & code order
996    predBB.insertOut(testBB);
997    ir.cfg.linkInCodeOrder(predBB, testBB);
998    testBB.insertOut(succBB);
999    testBB.insertOut(resolveBB);
1000    ir.cfg.linkInCodeOrder(testBB, succBB);
1001    resolveBB.insertOut(testBB);              // backedge
1002    ir.cfg.addLastInCodeOrder(resolveBB);  // stick resolution code in outer space.
1003    return testBB.lastInstruction();
1004  }
1005
1006  /**
1007   * Insert a binary instruction before s in the instruction stream.
1008   * @param s the instruction to insert before
1009   * @param ir the containing IR
1010   * @param operator the operator to insert
1011   * @param type the type of the result
1012   * @param o1 the first operand
1013   * @param o2 the second operand
1014   * @return the result operand of the inserted instruction
1015   */
1016  public static RegisterOperand insertBinary(Instruction s, IR ir, Operator operator,
1017                                                 TypeReference type, Operand o1, Operand o2) {
1018    RegisterOperand t = ir.regpool.makeTemp(type);
1019    s.insertBefore(CPOS(s, Binary.create(operator, t, o1, o2)));
1020    return t.copyD2U();
1021  }
1022
1023  /**
1024   * Insert a unary instruction before s in the instruction stream.
1025   * @param s the instruction to insert before
1026   * @param ir the containing IR
1027   * @param operator the operator to insert
1028   * @param type the type of the result
1029   * @param o1 the operand
1030   * @return the result operand of the inserted instruction
1031   */
1032  static RegisterOperand InsertUnary(Instruction s, IR ir, Operator operator, TypeReference type,
1033                                         Operand o1) {
1034    RegisterOperand t = ir.regpool.makeTemp(type);
1035    s.insertBefore(CPOS(s, Unary.create(operator, t, o1)));
1036    return t.copyD2U();
1037  }
1038
1039  /**
1040   * Insert a guarded unary instruction before s in the instruction stream.
1041   * @param s the instruction to insert before
1042   * @param ir the containing IR
1043   * @param operator the operator to insert
1044   * @param type the type of the result
1045   * @param o1 the operand
1046   * @param guard the guard operand
1047   * @return the result operand of the inserted instruction
1048   */
1049  static RegisterOperand InsertGuardedUnary(Instruction s, IR ir, Operator operator,
1050                                                TypeReference type, Operand o1, Operand guard) {
1051    RegisterOperand t = ir.regpool.makeTemp(type);
1052    s.insertBefore(GuardedUnary.create(operator, t, o1, guard));
1053    return t.copyD2U();
1054  }
1055
1056  /**
1057   * Insert a load off the JTOC before s in the instruction stream.
1058   * @param s the instruction to insert before
1059   * @param ir the containing IR
1060   * @param operator the operator to insert
1061   * @param type the type of the result
1062   * @param offset the offset to load at
1063   * @return the result operand of the inserted instruction
1064   */
1065  static RegisterOperand InsertLoadOffsetJTOC(Instruction s, IR ir, Operator operator,
1066                                                  TypeReference type, Offset offset) {
1067    return InsertLoadOffset(s,
1068                            ir,
1069                            operator,
1070                            type,
1071                            ir.regpool.makeJTOCOp(),
1072                            AC(offset),
1073                            new LocationOperand(offset),
1074                            null);
1075  }
1076
1077  /**
1078   * Insert a load off the JTOC before s in the instruction stream.
1079   * @param s the instruction to insert before
1080   * @param ir the containing IR
1081   * @param operator the operator to insert
1082   * @param type the type of the result
1083   * @param offset the offset to load at
1084   * @return the result operand of the inserted instruction
1085   */
1086  static RegisterOperand InsertLoadOffsetJTOC(Instruction s, IR ir, Operator operator,
1087                                                  TypeReference type, Operand offset) {
1088    return InsertLoadOffset(s, ir, operator, type, ir.regpool.makeJTOCOp(), offset, null, null);
1089  }
1090
1091  /**
1092   * Insert a load off before s in the instruction stream.
1093   * @param s the instruction to insert before
1094   * @param ir the containing IR
1095   * @param operator the operator to insert
1096   * @param type the type of the result
1097   * @param reg2 the base to load from
1098   * @param offset the offset to load at
1099   * @return the result operand of the inserted instruction
1100   */
1101  static RegisterOperand InsertLoadOffset(Instruction s, IR ir, Operator operator,
1102                                              TypeReference type, Operand reg2, Offset offset) {
1103    return InsertLoadOffset(s, ir, operator, type, reg2, offset, null, null);
1104  }
1105
1106  /**
1107   * Insert a load off before s in the instruction stream.
1108   * @param s the instruction to insert before
1109   * @param ir the containing IR
1110   * @param operator the operator to insert
1111   * @param type the type of the result
1112   * @param reg2 the base to load from
1113   * @param offset the offset to load at
1114   * @param guard the guard operand
1115   * @return the result operand of the inserted instruction
1116   */
1117  static RegisterOperand InsertLoadOffset(Instruction s, IR ir, Operator operator,
1118                                              TypeReference type, Operand reg2, Offset offset,
1119                                              Operand guard) {
1120    return InsertLoadOffset(s, ir, operator, type, reg2, offset, null, guard);
1121  }
1122
1123  /**
1124   * Insert a load off before s in the instruction stream.
1125   * @param s the instruction to insert before
1126   * @param ir the containing IR
1127   * @param operator the operator to insert
1128   * @param type the type of the result
1129   * @param reg2 the base to load from
1130   * @param offset the offset to load at
1131   * @param loc the location operand
1132   * @param guard the guard operand
1133   * @return the result operand of the inserted instruction
1134   */
1135  static RegisterOperand InsertLoadOffset(Instruction s, IR ir, Operator operator,
1136                                              TypeReference type, Operand reg2, Offset offset,
1137                                              LocationOperand loc, Operand guard) {
1138    return InsertLoadOffset(s, ir, operator, type, reg2, AC(offset), loc, guard);
1139  }
1140
1141  /**
1142   * Insert a load off before s in the instruction stream.
1143   * @param s the instruction to insert before
1144   * @param ir the containing IR
1145   * @param operator the operator to insert
1146   * @param type the type of the result
1147   * @param reg2 the base to load from
1148   * @param offset the offset to load at
1149   * @param loc the location operand
1150   * @param guard the guard operand
1151   * @return the result operand of the inserted instruction
1152   */
1153  static RegisterOperand InsertLoadOffset(Instruction s, IR ir, Operator operator,
1154                                              TypeReference type, Operand reg2, Operand offset,
1155                                              LocationOperand loc, Operand guard) {
1156    RegisterOperand regTarget = ir.regpool.makeTemp(type);
1157    Instruction s2 = Load.create(operator, regTarget, reg2, offset, loc, guard);
1158    s.insertBefore(s2);
1159    return regTarget.copyD2U();
1160  }
1161
1162  static Operand getTIB(Instruction s, IR ir, Operand obj, Operand guard) {
1163    if (obj.isObjectConstant()) {
1164      // NB Constant types must already be resolved
1165      try {
1166        RVMType type = obj.getType().resolve();
1167        return new TIBConstantOperand(type);
1168      } catch (NoClassDefFoundError e) {
1169        if (VM.runningVM) throw e;
1170        // Class not found during bootstrap due to chasing a class
1171        // only valid in the bootstrap JVM
1172      }
1173    }
1174    RegisterOperand res = ir.regpool.makeTemp(TypeReference.TIB);
1175    Instruction s2 = GuardedUnary.create(GET_OBJ_TIB, res, obj, guard);
1176    s.insertBefore(s2);
1177    return res.copyD2U();
1178  }
1179
1180  static Operand getTIB(Instruction s, IR ir, RVMType type) {
1181    return new TIBConstantOperand(type);
1182    //return getTIB(s, ir, new TypeOperand(type));
1183  }
1184
1185  static Operand getTIB(Instruction s, IR ir, TypeOperand type) {
1186    RVMType t = type.getVMType();
1187    if (VM.BuildForIA32 && !MOVES_TIBS && VM.runningVM && t != null && t.isResolved()) {
1188      Address addr = Magic.objectAsAddress(t.getTypeInformationBlock());
1189      return new AddressConstantOperand(addr);
1190    } else if (!t.isResolved()) {
1191      RegisterOperand res = ir.regpool.makeTemp(TypeReference.TIB);
1192      s.insertBefore(Unary.create(GET_CLASS_TIB, res, type));
1193      return res.copyD2U();
1194    } else {
1195      return new TIBConstantOperand(t);
1196    }
1197  }
1198
1199  static RegisterOperand getInstanceMethod(Instruction s, IR ir, Operand tib, RVMMethod method) {
1200    return InsertLoadOffset(s, ir, REF_LOAD, TypeReference.CodeArray, tib, method.getOffset());
1201  }
1202
1203  public static RegisterOperand getField(Instruction s, IR ir, RegisterOperand obj, RVMField field) {
1204    return getField(s, ir, obj, field, null);
1205  }
1206
1207  static RegisterOperand getField(Instruction s, IR ir, RegisterOperand obj, RVMField field,
1208                                      Operand guard) {
1209    return InsertLoadOffset(s,
1210                            ir,
1211                            IRTools.getLoadOp(field.getType(), field.isStatic()),
1212                            field.getType(),
1213                            obj,
1214                            field.getOffset(),
1215                            new LocationOperand(field),
1216                            guard);
1217  }
1218
1219  /*  RRB 100500 */
1220
1221  static RegisterOperand getSpecialMethod(Instruction s, IR ir, int smid) {
1222    //  First, get the pointer to the JTOC offset pointing to the
1223    //  specialized Method table
1224    RegisterOperand reg =
1225        InsertLoadOffsetJTOC(s,
1226                             ir,
1227                             REF_LOAD,
1228                             TypeReference.JavaLangObjectArray,
1229                             AosEntrypoints.specializedMethodsField.getOffset());
1230    RegisterOperand instr =
1231        InsertLoadOffset(s,
1232                         ir,
1233                         REF_LOAD,
1234                         TypeReference.CodeArray,
1235                         reg,
1236                         Offset.fromIntZeroExtend(smid << LOG_BYTES_IN_INT));
1237    return instr;
1238  }
1239
1240  /**
1241   * Expand symbolic SysCall target into a chain of loads from the bootrecord to
1242   * the desired target address.
1243   *
1244   * @param s the call instruction
1245   * @param ir the governing IR
1246   */
1247  public static void expandSysCallTarget(Instruction s, IR ir) {
1248    MethodOperand sysM = Call.getMethod(s);
1249    if (sysM.getMemberRef().isFieldReference()) {
1250      RegisterOperand t1 = getStatic(s, ir, Entrypoints.the_boot_recordField);
1251      RVMField target = sysM.getMemberRef().asFieldReference().resolve();
1252      Operand ip = getField(s, ir, t1, target);
1253      Call.setAddress(s, ip);
1254    }
1255  }
1256
1257  public static RegisterOperand getStatic(Instruction s, IR ir, RVMField field) {
1258    return InsertLoadOffsetJTOC(s,
1259                                ir,
1260                                IRTools.getLoadOp(field.getType(), field.isStatic()),
1261                                field.getType(),
1262                                field.getOffset());
1263  }
1264}