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