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