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.liveness;
014    
015    import org.jikesrvm.compilers.opt.ir.BasicBlock;
016    import org.jikesrvm.compilers.opt.ir.Instruction;
017    import org.jikesrvm.compilers.opt.ir.Register;
018    import org.jikesrvm.compilers.opt.ir.operand.RegisterOperand;
019    import org.jikesrvm.compilers.opt.regalloc.LiveIntervalElement;
020    
021    /**
022     * This class contains useful methods for managing liveIntervals.
023     */
024    final class LiveInterval {
025    
026      private static final boolean DEBUG = false;
027    
028      /**
029       * This method iterates over each element in the the passed live set.
030       * For each element, it checks if an existing live interval node for
031       * the basic block passed exists.  If one does not exist, it creates
032       * a node with the end instruction being "inst".  If one already exists
033       * no action is taken.
034       *
035       * @param set  the set of registers, encoded as a LiveSet object
036       * @param block the basic block
037       * @param inst the instruction where the register's live range ends,
038       *             null represents the end of the basic block
039       */
040      public static void createEndLiveRange(LiveSet set, BasicBlock block, Instruction inst) {
041        if (DEBUG) {
042          if (inst == null) {
043            System.out.println("The following are live on exit of block " + block.getNumber() + "\n" + set);
044          } else {
045            System.out.println("The following are live ending at inst\n  " +
046                               inst +
047                               " for block " +
048                               block.getNumber() +
049                               "\n" +
050                               set);
051          }
052        }
053    
054        LiveSetEnumerator lsEnum = set.enumerator();
055        while (lsEnum.hasMoreElements()) {
056          RegisterOperand regOp = lsEnum.nextElement();
057          createEndLiveRange(regOp.getRegister(), block, inst);
058        }
059      }
060    
061      /**
062       * This method checks if an existing unresolved live interval node, i.e.,
063       * one that has an end instruction, but no beginning instruction, is present
064       * for the register and basic block passed.  If one does not exist, it
065       * creates a node with the end instruction being <code>inst</code>.  If one
066       * already exists no action is taken.
067       *
068       * @param reg   The register
069       * @param block The basic block
070       * @param inst  The end instruction to use, if we have to create a neode.
071       */
072      public static void createEndLiveRange(Register reg, BasicBlock block, Instruction inst) {
073    
074        if (DEBUG) {
075          System.out.println("Marking Register " +
076                             reg +
077                             "'s live range as ENDing at instruction\n   " +
078                             inst +
079                             " in block #" +
080                             block.getNumber());
081          printLiveIntervalList(block);
082        }
083    
084        if (!containsUnresolvedElement(block, reg)) {
085          LiveIntervalElement elem = new LiveIntervalElement(reg, null, inst);
086    
087          // add elem to the list for the basic block
088          block.prependLiveIntervalElement(elem);
089        }
090      }
091    
092      /**
093       * This method finds the LiveInterval node for the register and basic block
094       * passed.  It then sets the begin instruction to the instruction passed
095       * and moves the node to the proper place on the list block list.
096       * (The block list is sorted by "begin" instruction.
097       *
098       * @param reg   the register of interest
099       * @param inst  the "begin" instruction
100       * @param block the basic block of interest
101       */
102      public static void setStartLiveRange(Register reg, Instruction inst, BasicBlock block) {
103        if (DEBUG) {
104          System.out.println("Marking Register " +
105                             reg +
106                             "'s live range as STARTing at instruction\n   " +
107                             inst +
108                             " in block #" +
109                             block.getNumber());
110        }
111    
112        LiveIntervalElement prev = null;
113        LiveIntervalElement elem = block.getFirstLiveIntervalElement();
114        while (elem != null) {
115          if (elem.getRegister() == reg && elem.getBegin() == null) {
116            break;
117          }
118    
119          prev = elem;
120          elem = elem.getNext();
121        }
122    
123        if (elem != null) {
124          elem.setBegin(inst);
125    
126          // we want the list sorted by "begin" instruction.  Since
127          // we are *assuming* that we are called in a traversal that is
128          // visiting instructions backwards, the instr passed will always
129          // be the most recent.  Thus, we move "elem" to the front of the list.
130          if (prev != null) {
131            // remove elem from current position
132            prev.setNext(elem.getNext());
133    
134            // add it to the begining
135            block.prependLiveIntervalElement(elem);
136          }
137    
138          // if prev == null, the element is already first in the list!
139        } else {
140          // if we didn't find it, it means we have a def that is not later
141          // used, i.e., a dead assignment.  This may exist because the
142          // instruction has side effects such as a function call or a PEI
143          // In this case, we create a LiveIntervalElement node with begining
144          // and ending instruction "inst"
145          LiveIntervalElement newElem = new LiveIntervalElement(reg, inst, inst);
146          block.prependLiveIntervalElement(newElem);
147        }
148    
149        if (DEBUG) {
150          System.out.println("after add");
151          printLiveIntervalList(block);
152        }
153      }
154    
155      /**
156       * This method finds any LiveInterval node that does not have a start
157       * instruction (it is null) and moves this node to the front of the list.
158       *
159       * @param block the basic block of interest
160       */
161      public static void moveUpwardExposedRegsToFront(BasicBlock block) {
162    
163        LiveIntervalElement prev = block.getFirstLiveIntervalElement();
164        if (prev == null) {
165          return;
166        }
167    
168        // The first element is already at the front, so move on to the next one
169        LiveIntervalElement elem = prev.getNext();
170    
171        while (elem != null) {
172          if (elem.getBegin() == null) {
173            // remove elem from current position
174            prev.setNext(elem.getNext());
175    
176            // add it to the begining, se
177            block.prependLiveIntervalElement(elem);
178    
179            // the next victum is the *new* one after prev
180            elem = prev.getNext();
181          } else {
182            prev = elem;
183            elem = elem.getNext();
184          }
185        }
186      }
187    
188      /**
189       * Check to see if an unresolved LiveIntervalElement node for the register
190       * passed exists for the basic block passed.
191       *
192       * @param block the block
193       * @param reg   the register of interest
194       * @return <code>true</code> if it does or <code>false</code>
195       *         if it does not
196       */
197      private static boolean containsUnresolvedElement(BasicBlock block, Register reg) {
198    
199        if (DEBUG) {
200          System.out.println("containsUnresolvedElement called, block: " + block + " register: " + reg);
201          printLiveIntervalList(block);
202        }
203    
204        for (LiveIntervalElement elem = block.getFirstLiveIntervalElement(); elem != null; elem = elem.getNext()) {
205          // if we got an element, down case it to LiveIntervalElement
206          if (elem.getRegister() == reg && elem.getBegin() == null) {
207            return true;
208          }
209        }
210        return false;
211      }
212    
213      /**
214       * Print the live intervals for a block.
215       *
216       * @param block the block
217       */
218      public static void printLiveIntervalList(BasicBlock block) {
219        System.out.println("Live Interval List for " + block);
220        for (LiveIntervalElement elem = block.getFirstLiveIntervalElement(); elem != null; elem = elem.getNext()) {
221          System.out.println("  " + elem);
222        }
223      }
224    }