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;
014
015import static org.jikesrvm.compilers.opt.ir.Operators.PHI;
016
017import java.util.Arrays;
018import java.util.Enumeration;
019
020import org.jikesrvm.VM;
021import org.jikesrvm.classloader.TypeReference;
022import org.jikesrvm.compilers.opt.ir.BasicBlock;
023import org.jikesrvm.compilers.opt.ir.IR;
024import org.jikesrvm.compilers.opt.ir.Instruction;
025import org.jikesrvm.compilers.opt.ir.Register;
026import org.jikesrvm.compilers.opt.ir.operand.Operand;
027import org.jikesrvm.compilers.opt.ir.operand.RegisterOperand;
028import org.vmmagic.pragma.NoInline;
029
030/**
031 * This class computes du-lists and associated information.
032 *
033 * <P> Note: DU operands are stored on the USE lists, but not the DEF
034 * lists.
035 */
036public final class DefUse {
037  static final boolean DEBUG = false;
038  static final boolean TRACE_DU_ACTIONS = false;
039  static final boolean SUPRESS_DU_FOR_PHYSICALS = true;
040
041  /**
042   * Clear defList, useList for an IR.
043   *
044   * @param ir the IR in question
045   */
046  public static void clearDU(IR ir) {
047    for (Register reg = ir.regpool.getFirstSymbolicRegister(); reg != null; reg = reg.getNext()) {
048      reg.defList = null;
049      reg.useList = null;
050      reg.clearSeenUse();
051    }
052    for (Enumeration<Register> e = ir.regpool.getPhysicalRegisterSet().enumerateAll(); e.hasMoreElements();) {
053      Register reg = e.nextElement();
054      reg.defList = null;
055      reg.useList = null;
056      reg.clearSeenUse();
057    }
058
059    if (TRACE_DU_ACTIONS || DEBUG) {
060      VM.sysWrite("Cleared DU\n");
061    }
062  }
063
064  /**
065   * Compute the register list and def-use lists for a method.
066   *
067   * @param ir the IR in question
068   */
069  @NoInline
070  public static void computeDU(IR ir) {
071    // Clear old register list (if any)
072    clearDU(ir);
073    // Create register defList and useList
074    for (Instruction instr = ir.firstInstructionInCodeOrder(); instr != null; instr =
075        instr.nextInstructionInCodeOrder()) {
076
077      Enumeration<Operand> defs = instr.getPureDefs();
078      Enumeration<Operand> uses = instr.getUses();
079
080      while (defs.hasMoreElements()) {
081        Operand op = defs.nextElement();
082        if (op instanceof RegisterOperand) {
083          RegisterOperand rop = (RegisterOperand) op;
084          recordDef(rop);
085        }
086      }         // for ( defs = ... )
087
088      while (uses.hasMoreElements()) {
089        Operand op = uses.nextElement();
090        if (op instanceof RegisterOperand) {
091          RegisterOperand rop = (RegisterOperand) op;
092          recordUse(rop);
093        }
094      }         // for ( uses = ... )
095    }           // for ( instr = ... )
096    // Remove any symbloic registers with no uses/defs from
097    // the register pool.  We'll waste analysis time keeping them around.
098    Register next;
099    for (Register reg = ir.regpool.getFirstSymbolicRegister(); reg != null; reg = next) {
100      next = reg.getNext();
101      if (reg.defList == null && reg.useList == null) {
102        if (DEBUG) {
103          VM.sysWrite("Removing " + reg + " from the register pool\n");
104        }
105        ir.regpool.removeRegister(reg);
106      }
107    }
108  }
109
110  /**
111   * Record a use of a register
112   * @param regOp the operand that uses the register
113   */
114  public static void recordUse(RegisterOperand regOp) {
115    Register reg = regOp.getRegister();
116    regOp.setNext(reg.useList);
117    reg.useList = regOp;
118    reg.useCount++;
119  }
120
121  /**
122   * Record a def/use of a register
123   * TODO: For now we just pretend this is a use!!!!
124   *
125   * @param regOp the operand that uses the register
126   */
127  public static void recordDefUse(RegisterOperand regOp) {
128    Register reg = regOp.getRegister();
129    if (SUPRESS_DU_FOR_PHYSICALS && reg.isPhysical()) return;
130    regOp.setNext(reg.useList);
131    reg.useList = regOp;
132  }
133
134  /**
135   * Record a def of a register
136   * @param regOp the operand that uses the register
137   */
138  public static void recordDef(RegisterOperand regOp) {
139    Register reg = regOp.getRegister();
140    if (SUPRESS_DU_FOR_PHYSICALS && reg.isPhysical()) return;
141    regOp.setNext(reg.defList);
142    reg.defList = regOp;
143  }
144
145  /**
146   * Record that a use of a register no longer applies
147   * @param regOp the operand that uses the register
148   */
149  public static void removeUse(RegisterOperand regOp) {
150    Register reg = regOp.getRegister();
151    if (SUPRESS_DU_FOR_PHYSICALS && reg.isPhysical()) return;
152    if (regOp == reg.useList) {
153      reg.useList = reg.useList.getNext();
154    } else {
155      RegisterOperand prev = reg.useList;
156      RegisterOperand curr = prev.getNext();
157      while (curr != regOp) {
158        prev = curr;
159        curr = curr.getNext();
160      }
161      prev.setNext(curr.getNext());
162    }
163    reg.useCount--;
164    if (DEBUG) {
165      VM.sysWrite("removed a use " + regOp.instruction + "\n");
166      printUses(reg);
167    }
168  }
169
170  /**
171   * Record that a def of a register no longer applies
172   * @param regOp the operand that uses the register
173   */
174  public static void removeDef(RegisterOperand regOp) {
175    Register reg = regOp.getRegister();
176    if (SUPRESS_DU_FOR_PHYSICALS && reg.isPhysical()) return;
177    if (regOp == reg.defList) {
178      reg.defList = reg.defList.getNext();
179    } else {
180      RegisterOperand prev = reg.defList;
181      RegisterOperand curr = prev.getNext();
182      while (curr != regOp) {
183        prev = curr;
184        curr = curr.getNext();
185      }
186      prev.setNext(curr.getNext());
187    }
188    if (DEBUG) {
189      VM.sysWrite("removed a def " + regOp.instruction + "\n");
190      printDefs(reg);
191    }
192  }
193
194  /**
195   *  This code changes the use in <code>origRegOp</code> to use
196   *    the use in <code>newRegOp</code>.
197   *
198   *  <p> If the type of <code>origRegOp</code> is not a reference, but the
199   *  type of <code>newRegOp</code> is a reference, we need to update
200   *  <code>origRegOp</code> to be a reference.
201   *  Otherwise, the GC map code will be incorrect.   -- Mike Hind
202   *  @param origRegOp the register operand to change
203   *  @param newRegOp the register operand to use for the change
204   */
205  public static void transferUse(RegisterOperand origRegOp, RegisterOperand newRegOp) {
206    if (VM.VerifyAssertions) {
207      VM._assert(origRegOp.getRegister().getType() == newRegOp.getRegister().getType());
208    }
209    Instruction inst = origRegOp.instruction;
210    if (DEBUG) {
211      VM.sysWrite("Transfering a use of " + origRegOp + " in " + inst + " to " + newRegOp + "\n");
212    }
213    removeUse(origRegOp);
214    // check to see if the regOp type is NOT a ref, but the newRegOp type
215    // is a reference.   This can occur because of magic calls.
216    if (!origRegOp.getType().isReferenceType() && newRegOp.getType().isReferenceType()) {
217      // clone the newRegOp object and use it to replace the regOp object
218      RegisterOperand copiedRegOp = (RegisterOperand) newRegOp.copy();
219      inst.replaceOperand(origRegOp, copiedRegOp);
220      recordUse(copiedRegOp);
221    } else {
222      // just copy the register
223      origRegOp.setRegister(newRegOp.getRegister());
224      if (newRegOp.getType() != TypeReference.ObjectReference &&
225          !newRegOp.getType().isUnboxedType() && !origRegOp.isPreciseType()) {
226        // copy type information from new to orig unless its an unboxed type
227        // (we don't want to copy type information for unboxed types as it is
228        // likely the result of inlining new) or the type of the original is
229        // precise
230        origRegOp.copyTypeFrom(newRegOp);
231      }
232      recordUse(origRegOp);
233    }
234    if (DEBUG) {
235      printUses(origRegOp.getRegister());
236      printUses(newRegOp.getRegister());
237    }
238  }
239
240  public static void removeInstructionAndUpdateDU(Instruction s) {
241    for (Enumeration<Operand> e = s.getPureDefs(); e.hasMoreElements();) {
242      Operand op = e.nextElement();
243      if (op instanceof RegisterOperand) {
244        removeDef((RegisterOperand) op);
245      }
246    }
247    for (Enumeration<Operand> e = s.getUses(); e.hasMoreElements();) {
248      Operand op = e.nextElement();
249      if (op instanceof RegisterOperand) {
250        removeUse((RegisterOperand) op);
251      }
252    }
253    s.remove();
254  }
255
256  public static void updateDUForNewInstruction(Instruction s) {
257    for (Enumeration<Operand> e = s.getPureDefs(); e.hasMoreElements();) {
258      Operand op = e.nextElement();
259      if (op instanceof RegisterOperand) {
260        recordDef((RegisterOperand) op);
261      }
262    }
263    for (Enumeration<Operand> e = s.getUses(); e.hasMoreElements();) {
264      Operand op = e.nextElement();
265      if (op instanceof RegisterOperand) {
266        recordUse((RegisterOperand) op);
267      }
268    }
269  }
270
271  public static void replaceInstructionAndUpdateDU(Instruction oldI, Instruction newI) {
272    oldI.insertBefore(newI);
273    removeInstructionAndUpdateDU(oldI);
274    updateDUForNewInstruction(newI);
275  }
276
277  public static Enumeration<RegisterOperand> uses(Register reg) {
278    return new RegOpListWalker(reg.useList);
279  }
280
281  public static Enumeration<RegisterOperand> defs(Register reg) {
282    return new RegOpListWalker(reg.defList);
283  }
284
285  static boolean exactlyOneUse(Register reg) {
286    return (reg.useList != null) && (reg.useList.getNext() == null);
287  }
288
289  static void printDefs(Register reg) {
290    VM.sysWrite("Definitions of " + reg + '\n');
291    for (Enumeration<RegisterOperand> e = defs(reg); e.hasMoreElements();) {
292      VM.sysWrite("\t" + e.nextElement().instruction + "\n");
293    }
294  }
295
296  static void printUses(Register reg) {
297    VM.sysWrite("Uses of " + reg + '\n');
298    for (Enumeration<RegisterOperand> e = uses(reg); e.hasMoreElements();) {
299      VM.sysWrite("\t" + e.nextElement().instruction + "\n");
300    }
301  }
302
303  /**
304   * Recompute <code> isSSA </code> for all registers by traversing register
305   * list.
306   * NOTE: the DU MUST be computed BEFORE calling this function
307   *
308   * @param ir the IR in question
309   */
310  public static void recomputeSSA(IR ir) {
311    // Use register /ist to enumerate register objects (FAST)
312    for (Register reg = ir.regpool.getFirstSymbolicRegister(); reg != null; reg = reg.getNext()) {
313      // Set isSSA = true iff reg has exactly one static definition.
314      reg.putSSA((reg.defList != null && reg.defList.getNext() == null));
315    }
316  }
317
318  /**
319   * Merges a register into another register and removes the
320   * merged register from the DU information.
321   *
322   * @param reg1 the register that is being merged into
323   * @param reg2 the register that's being merged (and then removed from the
324   *  DU information)
325   * @param ir the governing IR
326   */
327  public static void mergeRegisters(IR ir, Register reg1, Register reg2) {
328    RegisterOperand lastOperand;
329    if (reg1 == reg2) {
330      return;
331    }
332    if (DEBUG) {
333      VM.sysWrite("Merging " + reg2 + " into " + reg1 + "\n");
334      printDefs(reg2);
335      printUses(reg2);
336      printDefs(reg1);
337      printUses(reg1);
338    }
339    // first loop through defs of reg2 (currently, there will only be one def)
340    lastOperand = null;
341    for (RegisterOperand def = reg2.defList; def != null; lastOperand = def, def = def.getNext()) {
342      // Change def to refer to reg1 instead
343      def.setRegister(reg1);
344      // Track lastOperand
345      lastOperand = def;
346    }
347    if (lastOperand != null) {
348      // Set reg1.defList = concat(reg2.defList, reg1.deflist)
349      lastOperand.setNext(reg1.defList);
350      reg1.defList = reg2.defList;
351    }
352    // now loop through uses
353    lastOperand = null;
354    for (RegisterOperand use = reg2.useList; use != null; use = use.getNext()) {
355      // Change use to refer to reg1 instead
356      use.setRegister(reg1);
357      // Track lastOperand
358      lastOperand = use;
359    }
360    if (lastOperand != null) {
361      // Set reg1.useList = concat(reg2.useList, reg1.uselist)
362      lastOperand.setNext(reg1.useList);
363      reg1.useList = reg2.useList;
364    }
365    // Remove reg2 from RegisterPool
366    ir.regpool.removeRegister(reg2);
367    if (DEBUG) {
368      VM.sysWrite("Merge complete\n");
369      printDefs(reg1);
370      printUses(reg1);
371    }
372  }
373
374  /**
375   * Recompute spansBasicBlock flags for all registers.
376   *
377   * @param ir the IR in question
378   */
379  public static void recomputeSpansBasicBlock(IR ir) {
380    // clear fields
381    for (Register reg = ir.regpool.getFirstSymbolicRegister(); reg != null; reg = reg.getNext()) {
382      reg.clearSpansBasicBlock();
383    }
384
385    int[] lastBBNums = new int[ir.regpool.getTotalNumberOfRegisters()];
386    Arrays.fill(lastBBNums, -1);
387    // iterate over the basic blocks
388    for (BasicBlock bb = ir.firstBasicBlockInCodeOrder(); bb != null; bb = bb.nextBasicBlockInCodeOrder()) {
389      int bbNum = bb.getNumber();
390      // enumerate the instructions in the basic block
391      for (Enumeration<Instruction> e = bb.forwardRealInstrEnumerator(); e.hasMoreElements();) {
392        Instruction inst = e.nextElement();
393        // check each Operand in the instruction
394        for (Enumeration<Operand> ops = inst.getOperands(); ops.hasMoreElements();) {
395          Operand op = ops.nextElement();
396          if (op instanceof RegisterOperand) {
397            Register reg = ((RegisterOperand) op).getRegister();
398            if (reg.isPhysical()) {
399              continue;
400            }
401            if (reg.spansBasicBlock()) {
402              continue;
403            }
404            if (seenInDifferentBlock(reg, bbNum, lastBBNums)) {
405              reg.setSpansBasicBlock();
406              continue;
407            }
408            if (inst.operator() == PHI) {
409              reg.setSpansBasicBlock();
410              continue;
411            }
412            logAppearance(reg, bbNum, lastBBNums);
413          }
414        }
415      }
416    }
417  }
418
419  /**
420   * Mark that we have seen a register in a particular
421   * basic block.
422   *
423   * @param reg the register
424   * @param bbNum the number of the basic block
425   * @param bbNums last block were each register was seen
426   */
427  private static void logAppearance(Register reg, int bbNum, int[] bbNums) {
428    bbNums[reg.number] = bbNum;
429  }
430
431  /**
432   * @param reg the register
433   * @param bbNum the number of the basic block
434   * @param bbNums last block were each register was seen
435   * @return {@code true} if the register was seen in a different basic block
436   *  than the one that was passed to this method
437   */
438  private static boolean seenInDifferentBlock(Register reg, int bbNum, int[] bbNums) {
439    int bb = bbNums[reg.number];
440    return (bb != -1) && (bb != bbNum);
441  }
442
443  /**
444   * Utility class to encapsulate walking a use/def list.
445   */
446  private static final class RegOpListWalker implements Enumeration<RegisterOperand> {
447
448    private RegisterOperand current;
449
450    RegOpListWalker(RegisterOperand start) {
451      current = start;
452    }
453
454    @Override
455    public boolean hasMoreElements() {
456      return current != null;
457    }
458
459    @Override
460    public RegisterOperand nextElement() {
461      if (current == null) raiseNoSuchElementException();
462      RegisterOperand tmp = current;
463      current = current.getNext();
464      return tmp;
465    }
466
467    @NoInline
468    private static void raiseNoSuchElementException() {
469      throw new java.util.NoSuchElementException("RegOpListWalker");
470    }
471  }
472}