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 intruction 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 }