1 pnkfelix 1.1.2.1 package harpoon.Analysis.Instr;
  2 pnkfelix 1.1.2.1 
  3 pnkfelix 1.1.2.1 import harpoon.Analysis.Instr.AppelRegAllocClasses.Web;
  4 pnkfelix 1.1.2.1 import harpoon.Analysis.Instr.AppelRegAllocClasses.Node;
  5 pnkfelix 1.1.2.1 import harpoon.Analysis.Instr.AppelRegAllocClasses.NodeIter;
  6 pnkfelix 1.1.2.1 
  7 pnkfelix 1.1.2.1 import harpoon.Analysis.Loops.Loops;
  8 pnkfelix 1.1.2.1 import harpoon.Analysis.Loops.LoopFinder;
  9 pnkfelix 1.1.2.1 
 10 pnkfelix 1.1.2.1 import harpoon.IR.Assem.Instr;
 11 pnkfelix 1.1.2.1 
 12 cananian 1.5     import net.cscott.jutil.GenericMultiMap;
 13 cananian 1.5     import net.cscott.jutil.CombineIterator;
 14 pnkfelix 1.1.2.1 import harpoon.Util.Util;
 15 pnkfelix 1.1.2.1 
 16 pnkfelix 1.1.2.1 import harpoon.Temp.Temp;
 17 pnkfelix 1.1.2.1 
 18 pnkfelix 1.1.2.1 import java.util.Collection;
 19 pnkfelix 1.1.2.1 import java.util.Map;
 20 pnkfelix 1.1.2.1 import java.util.AbstractCollection;
 21 pnkfelix 1.1.2.1 import java.util.ArrayList;
 22 pnkfelix 1.1.2.1 import java.util.HashMap;
 23 pnkfelix 1.1.2.1 import java.util.Iterator;
 24 pnkfelix 1.1.2.1 
 25 pnkfelix 1.1.2.1 /** Abstracts away the heuristic used for deciding between
 26 pnkfelix 1.1.2.1     spill candidates during graph simplification.
 27 pnkfelix 1.1.2.1     <p>
 28 pnkfelix 1.1.2.1     See "Spill code minimization techniques for optimizing
 29 pnkfelix 1.1.2.1     compilers", Bernstein et. al
 30 pnkfelix 1.1.2.1 */
 31 pnkfelix 1.1.2.1 public class SpillHeuristics {
 32 pnkfelix 1.1.2.2 
 33 pnkfelix 1.1.2.3     public static boolean USE_ANANIAN_HEURISTIC = true;
 34 pnkfelix 1.1.2.2     public static boolean USE_CHAITIN_HEURISTIC = true;
 35 pnkfelix 1.1.2.3     public static boolean USE_PINTER_HEURISTICS = true;
 36 pnkfelix 1.1.2.2 
 37 pnkfelix 1.1.2.1     // Node n -> Set of Instr i, s.t. n is alive at i
 38 pnkfelix 1.1.2.1     private GenericMultiMap nodeToLiveAt = new GenericMultiMap();
 39 pnkfelix 1.1.2.1     private Map nestedLoopDepth;
 40 pnkfelix 1.1.2.1     
 41 pnkfelix 1.1.2.1     // shares state with the AppelRegAlloc class
 42 pnkfelix 1.1.2.1     AppelRegAlloc regalloc;
 43 pnkfelix 1.1.2.1     
 44 pnkfelix 1.1.2.1     SpillHeuristics(AppelRegAlloc ara) {
 45 pnkfelix 1.1.2.1         regalloc = ara;
 46 pnkfelix 1.1.2.1     }
 47 pnkfelix 1.1.2.1     
 48 pnkfelix 1.1.2.1     /** Resets the state of this in preparation for analysis on 
 49 pnkfelix 1.1.2.1         altered code.
 50 pnkfelix 1.1.2.1     */
 51 pnkfelix 1.1.2.1     void reset() {
 52 pnkfelix 1.1.2.1         // FSK: Lazily build these mappings...
 53 pnkfelix 1.1.2.1         nodeToLiveAt = null;
 54 pnkfelix 1.1.2.1         nestedLoopDepth = null;
 55 pnkfelix 1.1.2.1     }
 56 pnkfelix 1.1.2.1 
 57 pnkfelix 1.1.2.1     /** Instr -> Integer, val is loop nesting depth for the key (0 for
 58 pnkfelix 1.1.2.1         non-looped code).  Constructed on demand; access through method
 59 pnkfelix 1.1.2.1         call only. */
 60 pnkfelix 1.1.2.1     Map nestedLoopDepth() {
 61 pnkfelix 1.1.2.1         if (nestedLoopDepth == null)
 62 pnkfelix 1.1.2.1             nestedLoopDepth = buildNestedLoopDepth();
 63 pnkfelix 1.1.2.1         return nestedLoopDepth;
 64 pnkfelix 1.1.2.1     }
 65 pnkfelix 1.1.2.1     
 66 pnkfelix 1.1.2.1     private Map buildNestedLoopDepth() { 
 67 pnkfelix 1.1.2.1         // builds the nestedLoopDepth map, doing a breadth-first
 68 pnkfelix 1.1.2.1         // traversal of the loop tree.
 69 pnkfelix 1.1.2.1         HashMap depthMap = new HashMap();
 70 pnkfelix 1.1.2.1         LoopFinder root = new LoopFinder(regalloc.code);
 71 pnkfelix 1.1.2.1         
 72 pnkfelix 1.1.2.1         // List<Loops> where index of vector is the looping depth
 73 pnkfelix 1.1.2.1         // (thus the 0th elem is the root itself)
 74 pnkfelix 1.1.2.1         ArrayList level = new ArrayList();
 75 pnkfelix 1.1.2.1         level.add(root);
 76 pnkfelix 1.1.2.1         int depth = 0; // tracks the current level in the tree
 77 pnkfelix 1.1.2.1         while( ! level.isEmpty()) {
 78 pnkfelix 1.1.2.1             Iterator levelIter = level.iterator();
 79 pnkfelix 1.1.2.1             level = new ArrayList();
 80 pnkfelix 1.1.2.1             Integer currDepth = new Integer( depth );
 81 pnkfelix 1.1.2.1             while( levelIter.hasNext() ){
 82 pnkfelix 1.1.2.1                 Loops curr = (Loops) levelIter.next();
 83 pnkfelix 1.1.2.1                 level.addAll( curr.nestedLoops() );
 84 pnkfelix 1.1.2.1                 
 85 cananian 1.6                     for (Object iO : curr.loopExcElements()){
 86 cananian 1.6                         Instr i = (Instr) iO;
 87 cananian 1.3.2.1                     assert ! depthMap.keySet().contains( i );
 88 pnkfelix 1.1.2.1                     depthMap.put( i , currDepth );
 89 pnkfelix 1.1.2.1                 }
 90 pnkfelix 1.1.2.1             }
 91 pnkfelix 1.1.2.1             depth++;
 92 pnkfelix 1.1.2.1         }
 93 pnkfelix 1.1.2.1 
 94 pnkfelix 1.1.2.1         return depthMap;
 95 pnkfelix 1.1.2.1     }
 96 pnkfelix 1.1.2.1 
 97 pnkfelix 1.1.2.1     /** Returns a bunch of SpillHeuristic objects, with "cheap" ones 
 98 pnkfelix 1.1.2.1         in front.
 99 pnkfelix 1.1.2.1     */
100 pnkfelix 1.1.2.1     SpillHeuristic[] spillHeuristics() {
101 pnkfelix 1.1.2.1         SpillHeuristic[] hs = new SpillHeuristic[] { 
102 pnkfelix 1.1.2.1 
103 pnkfelix 1.1.2.2             USE_ANANIAN_HEURISTIC ?
104 pnkfelix 1.1.2.1             new SpillHeuristic() { double cost(Node m) {
105 pnkfelix 1.1.2.1                 return (1000*(m.web.defs.size()+m.web.uses.size() ) ) / m.degree;  }}
106 pnkfelix 1.1.2.2             : null
107 pnkfelix 1.1.2.1             ,
108 pnkfelix 1.1.2.1 
109 pnkfelix 1.1.2.2             USE_CHAITIN_HEURISTIC ?
110 pnkfelix 1.1.2.1             new SpillHeuristic() { double cost( Node m ) {  
111 pnkfelix 1.1.2.1                 return chaitinCost(m) / m.degree; }}
112 pnkfelix 1.1.2.2             : null
113 pnkfelix 1.1.2.1             , 
114 pnkfelix 1.1.2.2             USE_PINTER_HEURISTICS ?
115 pnkfelix 1.1.2.1             new SpillHeuristic() { double cost( Node m ) {  
116 pnkfelix 1.1.2.1                 return chaitinCost(m) / (m.degree * m.degree); }} 
117 pnkfelix 1.1.2.2             : null
118 pnkfelix 1.1.2.1             , 
119 pnkfelix 1.1.2.2             USE_PINTER_HEURISTICS ?
120 pnkfelix 1.1.2.1             new SpillHeuristic() { double cost( Node m ) { 
121 pnkfelix 1.1.2.1                 return chaitinCost(m) / ( area(m) * m.degree ); }} 
122 pnkfelix 1.1.2.2             : null
123 pnkfelix 1.1.2.1             , 
124 pnkfelix 1.1.2.2             USE_PINTER_HEURISTICS ? 
125 pnkfelix 1.1.2.1             new SpillHeuristic() { double cost( Node m ) { 
126 pnkfelix 1.1.2.2                 return chaitinCost(m) / ( area(m) * m.degree * m.degree ); }}
127 pnkfelix 1.1.2.2             : null
128 pnkfelix 1.1.2.1         };
129 pnkfelix 1.1.2.1         
130 pnkfelix 1.1.2.2         int nonnull=0;
131 pnkfelix 1.1.2.2         for(int i=0; i<hs.length; i++) 
132 pnkfelix 1.1.2.2             if (hs[i] != null) 
133 pnkfelix 1.1.2.2                 nonnull++;
134 pnkfelix 1.1.2.2         SpillHeuristic[] shs = new SpillHeuristic[nonnull];
135 pnkfelix 1.1.2.2         int j=0;
136 pnkfelix 1.1.2.2         for(int i=0; i<hs.length; i++) {
137 pnkfelix 1.1.2.2             if (hs[i] != null) {
138 pnkfelix 1.1.2.2                 shs[j] = hs[i];
139 pnkfelix 1.1.2.2                 j++;
140 pnkfelix 1.1.2.2             }
141 pnkfelix 1.1.2.2         }
142 cananian 1.3.2.1         assert j == nonnull;
143 pnkfelix 1.1.2.2         return shs;
144 pnkfelix 1.1.2.1     }
145 pnkfelix 1.1.2.1 
146 pnkfelix 1.1.2.1     /** Returns the loop nested depth of <code>i</code>. */
147 pnkfelix 1.1.2.1     int depth(Instr i){ return((Integer)nestedLoopDepth().get(i)).intValue(); }
148 pnkfelix 1.1.2.1     /** Returns the number of temporaries live at <code>i</code>. */
149 pnkfelix 1.1.2.1     int width(Instr i){ return liveAt(i).size(); }
150 pnkfelix 1.1.2.1 
151 pnkfelix 1.1.2.1 
152 pnkfelix 1.1.2.1     // wrapper for dealing with union'ing a large bitset with a small
153 pnkfelix 1.1.2.1     // appendage set.
154 pnkfelix 1.1.2.1     private class ExtremityCollection extends AbstractCollection {
155 pnkfelix 1.1.2.1         ArrayList appendage;
156 pnkfelix 1.1.2.1         Collection body;
157 pnkfelix 1.1.2.1         // shares state with big, but not with small.  I bet remove()
158 pnkfelix 1.1.2.1         // is pretty sketch...
159 pnkfelix 1.1.2.1         ExtremityCollection(Collection big, Collection small) {
160 pnkfelix 1.1.2.1             appendage = new ArrayList(small.size());
161 pnkfelix 1.1.2.1             for(Iterator iter=small.iterator(); iter.hasNext();){
162 pnkfelix 1.1.2.1                 Object s = iter.next();
163 pnkfelix 1.1.2.1                 if (!big.contains(s)) {
164 pnkfelix 1.1.2.1                     appendage.add(s);
165 pnkfelix 1.1.2.1                 }
166 pnkfelix 1.1.2.1             }
167 pnkfelix 1.1.2.1             body = big;
168 pnkfelix 1.1.2.1         }
169 pnkfelix 1.1.2.1         public Iterator iterator() { 
170 pnkfelix 1.1.2.1             return new CombineIterator(body.iterator(), appendage.iterator());
171 pnkfelix 1.1.2.1         }
172 pnkfelix 1.1.2.1         public int size() { return body.size() + appendage.size(); }
173 pnkfelix 1.1.2.1     }
174 pnkfelix 1.1.2.1     
175 pnkfelix 1.1.2.1     private Collection liveAt(Instr i) {
176 pnkfelix 1.1.2.1         // live-at(i) should be live-in(i) U defs(i), according to scott
177 pnkfelix 1.1.2.1         Collection liveTempC = regalloc.liveTemps.getLiveBefore(i);
178 pnkfelix 1.1.2.1         return new ExtremityCollection( liveTempC, i.defC() );
179 pnkfelix 1.1.2.1     }
180 pnkfelix 1.1.2.1 
181 pnkfelix 1.1.2.1     private void buildNodeToLiveAt() {
182 pnkfelix 1.1.2.1         nodeToLiveAt.clear();
183 pnkfelix 1.1.2.1         for(Iterator instrs = regalloc.instrs(); instrs.hasNext(); ){
184 pnkfelix 1.1.2.1             Instr i = (Instr) instrs.next();
185 pnkfelix 1.1.2.1             Collection liveAt = liveAt(i);
186 cananian 1.6                 for(Object tO : liveAt) {
187 cananian 1.6                     Temp t = (Temp) tO;
188 pnkfelix 1.1.2.1                 Collection rdefC = regalloc.rdefs.reachingDefs(i, t);
189 pnkfelix 1.1.2.1                 Collection webC = regalloc.tempToWebs.getValues( t );
190 cananian 1.6                     for(Object wO : webC){
191 cananian 1.6                         Web w = (Web) wO;
192 pnkfelix 1.1.2.1                     boolean intersect = false;
193 cananian 1.6                         for(Object defO : rdefC){
194 cananian 1.6                             Instr def = (Instr) defO;
195 pnkfelix 1.1.2.1                         if(w.defs.contains( def )){
196 pnkfelix 1.1.2.1                             intersect = true;
197 pnkfelix 1.1.2.1                             break;
198 pnkfelix 1.1.2.1                         }
199 pnkfelix 1.1.2.1                     }
200 pnkfelix 1.1.2.1                     if ( intersect ) {
201 pnkfelix 1.1.2.1                         // w has a def that reaches i, thus w is live-at i
202 pnkfelix 1.1.2.1                         Collection nodeC = (Collection) regalloc.nodesFor(w);
203 cananian 1.6                             for(Object nO : nodeC){
204 cananian 1.6                                 Node n = (Node) nO;
205 pnkfelix 1.1.2.1                             nodeToLiveAt.add( n, i );
206 pnkfelix 1.1.2.1                         }
207 pnkfelix 1.1.2.1                     }
208 pnkfelix 1.1.2.1                 }
209 pnkfelix 1.1.2.1             }
210 pnkfelix 1.1.2.1         }
211 pnkfelix 1.1.2.1     }
212 pnkfelix 1.1.2.1 
213 pnkfelix 1.1.2.1     protected abstract class SpillHeuristic {
214 pnkfelix 1.1.2.1         public String toString() { 
215 pnkfelix 1.1.2.1             return "SpillHeuristic<"
216 pnkfelix 1.1.2.1                 +"accumExpCost:"+accumExpCost 
217 pnkfelix 1.1.2.1                 +" maxExpSpills:"+maxExpSpills
218 pnkfelix 1.1.2.1                 +" actualCost:"+actualCost
219 pnkfelix 1.1.2.1                 +" actualSpills:"+actualSpills
220 pnkfelix 1.1.2.1                 +">";
221 pnkfelix 1.1.2.1         }
222 pnkfelix 1.1.2.1 
223 pnkfelix 1.1.2.1         double accumExpCost = 0.0;
224 pnkfelix 1.1.2.1         int maxExpSpills = 0;
225 pnkfelix 1.1.2.1 
226 pnkfelix 1.1.2.1         double actualCost = 0.0;
227 pnkfelix 1.1.2.1         int actualSpills = 0;
228 pnkfelix 1.1.2.1 
229 pnkfelix 1.1.2.1         HashMap instrToAreaCache = new HashMap();
230 pnkfelix 1.1.2.1         HashMap nodeToAreaCache = new HashMap();    
231 pnkfelix 1.1.2.1 
232 pnkfelix 1.1.2.1         void reset() { 
233 pnkfelix 1.1.2.1             accumExpCost = 0.0; 
234 pnkfelix 1.1.2.1             maxExpSpills = 0;
235 pnkfelix 1.1.2.1             actualCost = 0.0; 
236 pnkfelix 1.1.2.1             actualSpills = 0; 
237 pnkfelix 1.1.2.1             instrToAreaCache.clear();
238 pnkfelix 1.1.2.1             nodeToAreaCache.clear();
239 pnkfelix 1.1.2.1         }
240 pnkfelix 1.1.2.1         void expectSpill( Node m ) { 
241 pnkfelix 1.1.2.1             // IMPORTANT: don't confuse "accumExpCost" here (which is called
242 pnkfelix 1.1.2.1             // "h_i" in the paper) with "cost" in the paper (which is
243 pnkfelix 1.1.2.1             // called chaitinCost here)
244 pnkfelix 1.1.2.1             accumExpCost += chaitinCost( m ); 
245 pnkfelix 1.1.2.1             maxExpSpills++;
246 pnkfelix 1.1.2.1         }
247 pnkfelix 1.1.2.1 
248 pnkfelix 1.1.2.1         
249 pnkfelix 1.1.2.1         /** called when spill code is added for n . */
250 pnkfelix 1.1.2.1         void reallySpill( NodeIter ni ){
251 pnkfelix 1.1.2.1             while(ni.hasNext()) 
252 pnkfelix 1.1.2.1                 reallySpill(ni.next());
253 pnkfelix 1.1.2.1         }
254 pnkfelix 1.1.2.1         void reallySpill( Node n ){
255 pnkfelix 1.1.2.1             actualCost += chaitinCost(n);
256 pnkfelix 1.1.2.1             actualSpills++;
257 pnkfelix 1.1.2.1         }
258 pnkfelix 1.1.2.1 
259 pnkfelix 1.1.2.1         abstract double cost( Node m );
260 pnkfelix 1.1.2.1         
261 pnkfelix 1.1.2.1         double chaitinCost( Node m ) {
262 pnkfelix 1.1.2.1             double sum = 0.0;
263 cananian 1.6                 for(Object iO : m.web.defs){
264 cananian 1.6                     Instr i = (Instr) iO;
265 pnkfelix 1.1.2.1                 sum += Math.pow( 10.0, depth(i));
266 pnkfelix 1.1.2.1             }
267 cananian 1.6                 for(Object iO : m.web.uses){
268 cananian 1.6                     Instr i = (Instr) iO;
269 pnkfelix 1.1.2.1                 sum += Math.pow( 10.0, depth(i));
270 pnkfelix 1.1.2.1             }
271 pnkfelix 1.1.2.1             return sum;
272 pnkfelix 1.1.2.1         }
273 pnkfelix 1.1.2.1         double area( Node m ) {
274 pnkfelix 1.1.2.1             if (nodeToLiveAt == null) {
275 pnkfelix 1.1.2.1                 nodeToLiveAt = new GenericMultiMap();
276 pnkfelix 1.1.2.1                 buildNodeToLiveAt();
277 pnkfelix 1.1.2.1             }
278 pnkfelix 1.1.2.1 
279 pnkfelix 1.1.2.1             if (nodeToAreaCache.containsKey(m)) {
280 pnkfelix 1.1.2.1                 return ((Double)nodeToAreaCache.get(m)).doubleValue();
281 pnkfelix 1.1.2.1             } else {
282 pnkfelix 1.1.2.1                 double sum = 0.0;
283 pnkfelix 1.1.2.1                 Collection instrC = nodeToLiveAt.getValues( m );
284 cananian 1.6                     for(Object iO : instrC){
285 cananian 1.6                         Instr i = (Instr) iO;
286 pnkfelix 1.1.2.1                     
287 pnkfelix 1.1.2.1                     if (instrToAreaCache.containsKey(i)) {
288 pnkfelix 1.1.2.1                         sum += ((Double)instrToAreaCache.get(i)).doubleValue();
289 pnkfelix 1.1.2.1                     } else {
290 pnkfelix 1.1.2.1                         double val = (Math.pow(5.0, depth(i)) * width(i));
291 pnkfelix 1.1.2.1                         sum += val;
292 pnkfelix 1.1.2.1                         instrToAreaCache.put(i, new Double(val) );
293 pnkfelix 1.1.2.1                     }
294 pnkfelix 1.1.2.1                 }
295 pnkfelix 1.1.2.1                 nodeToAreaCache.put(m, new Double(sum));
296 pnkfelix 1.1.2.1                 return sum;
297 pnkfelix 1.1.2.1             }
298 pnkfelix 1.1.2.1         }
299 pnkfelix 1.1.2.1 
300 pnkfelix 1.1.2.1     }
301 cananian 1.2     }