switch to spaces only..
[IRC.git] / Robust / src / Analysis / Loops / LoopFinder.java
1 // LoopFinder.java, created Tue Jun 15 23:15:07 1999 by bdemsky
2 // Licensed under the terms of the GNU GPL; see COPYING for details.
3 // Copyright 1999 by Brian Demsky
4
5 package Analysis.Loops;
6
7 import IR.Flat.FlatMethod;
8 import IR.Flat.FlatNode;
9 import java.util.HashSet;
10 import java.util.Set;
11 import java.util.Stack;
12 import java.util.Hashtable;
13 import java.util.Iterator;
14 /**
15  * <code>LoopFinder</code> implements Dominator Tree Loop detection.
16  *
17  * @author  Brian Demsky <bdemsky@mit.edu>
18  * @version $Id: LoopFinder.java,v 1.5 2011/04/27 20:51:36 bdemsky Exp $
19  */
20
21 public class LoopFinder implements Loops {
22   DomTree dominator;
23   FlatMethod hc,lasthc;
24   HashSet setofloops;
25   Loop root;
26   Loop ptr;
27
28
29   /** Creates a new LoopFinder object.
30    * This call takes an HCode and a CFGrapher
31    * and returns a LoopFinder object
32    * at the root level.
33    */
34
35   public LoopFinder(FlatMethod hc) {
36     this.hc=hc;
37     this.dominator=new DomTree(hc,false);
38     analyze();
39     this.ptr=root;
40   }
41
42   /**This method is for internal use only.
43    *It returns a Loopfinder object at any level,
44    *but it doesn't regenerate the internal tree
45    *so any external calls would result in garbage.*/
46
47   private LoopFinder(FlatMethod hc, DomTree dt, Loop root, Loop ptr) {
48     this.lasthc=hc;
49     this.hc=hc;
50     this.dominator=dt;
51     this.root=root;
52     this.ptr=ptr;
53   }
54
55   /*-----------------------------*/
56
57   /**  This method returns the Root level loop for a given <code>HCode</code>.
58    *  Does the same thing as the constructor call, but for an existing
59    *  LoopFinder object.*/
60
61   public Loops getRootloop(FlatMethod hc) {
62     this.hc=hc;
63     analyze();
64     return new LoopFinder(hc,dominator,root,root);
65   }
66
67   /**  This method returns the entry point of the loop.
68    *   For the natural loops we consider, that is simply the header.
69    *   It returns a <code>Set</code> of <code>HCodeElement</code>s.*/
70
71   public Set loopEntrances() {
72     HashSet entries=new HashSet();
73     analyze();
74     entries.add(ptr.header);
75     return entries;
76   }
77
78
79   /**Returns a <code>Set</code> with all of the <code>HCodeElement</code>s of the loop and
80    *loops included entirely within this loop. */
81
82   public Set loopIncElements() {
83     analyze();
84     HashSet A=new HashSet(ptr.entries);
85     return A;
86   }
87
88   /** Returns all of the <code>HCodeElement</code>s of this loop that aren't in a nested
89    *  loop. This returns a <code>Set</code> of <code>HCodeElement</code>s.*/
90
91   public Set loopExcElements() {
92     analyze();
93     HashSet A=new HashSet(ptr.entries);
94     HashSet todo=new HashSet();
95     //Get the children
96     todo.addAll(ptr.children);
97
98     //Go down the tree
99     while(!todo.isEmpty()) {
100       Loop currptr=(Loop)todo.iterator().next();
101       todo.remove(currptr);
102       todo.addAll(currptr.children);
103       A.removeAll(currptr.entries);
104     }
105     return A;
106   }
107
108   /** Returns a <code>Set</code> of loops that are nested inside of this loop.*/
109
110   public Set nestedLoops() {
111     analyze();
112     HashSet L=new HashSet();
113     Iterator iterate=ptr.children.iterator();
114     while (iterate.hasNext())
115       L.add(new LoopFinder(hc,dominator,root,(Loop) iterate.next()));
116     return L;
117   }
118
119   /** Returns the <code>Loops</code> that contains this loop.
120    *  If this is the top level loop, this call returns a null pointer.*/
121
122   public Loops parentLoop() {
123     analyze();
124     if (ptr.parent!=null)
125       return new LoopFinder(hc,dominator,root,ptr.parent);
126     else return null;
127   }
128
129   /*---------------------------*/
130   // public information accessor methods.
131
132   /*---------------------------*/
133   // Analysis code.
134
135
136   /** Main analysis method. */
137
138   void analyze() {
139     //Have we analyzed this set before?
140     //If so, don't do it again!!!
141     if (hc!=lasthc) {
142
143       //Did the caller hand us a bogus object?
144       //If so, throw it something
145
146       lasthc=hc;
147
148       //Set up the top level loop, so we can fill it with HCodeElements
149       //as we go along
150       root=new Loop();
151       root.header=hc;
152
153       //Set up a WorkSet for storing loops before we build the
154       //nested loop tree
155       setofloops=new HashSet();
156
157
158       //Find loops
159       findloopheaders(hc);
160
161       //Build the nested loop tree
162       buildtree();
163     }
164   }
165   // end analysis.
166
167   void buildtree() {
168     //go through set of generated loops
169     while(!setofloops.isEmpty()) {
170       //Pull out one
171       Loop A=(Loop) setofloops.iterator().next();
172       setofloops.remove(A);
173
174       //Add it to the tree, complain if oddness
175       if (addnode(A, root)!=1)
176         System.out.println("Evil Error in LoopFinder while building tree.");
177     }
178   }
179
180   //Adds a node to the tree...Its recursive
181
182   int addnode(Loop A, Loop treenode) {
183     //Only need to go deeper if the header is contained in this loop
184     if (treenode.entries.contains(A.header))
185
186       //Do we share headers?
187       if (treenode.header!=A.header) {
188
189         //No...  Loop through our children to see if they want this
190         //node.
191
192         //Use integers for tri-state:
193         //0=not stored here, 1=stored and everything is good
194         //2=combined 2 natural loops with same header...need cleanup
195
196         int stored=0;
197         Iterator iterate=treenode.children.iterator();
198         Loop temp=new Loop();
199         while (iterate.hasNext()) {
200           temp=(Loop) iterate.next();
201           stored=addnode(A,temp);
202           if (stored!=0) break;
203         }
204
205         //See what our children did for us
206
207         if (stored==0) {
208           //We get a new child...
209           treenode.children.add(A);
210           temp=A;
211         }
212
213         //Need to do cleanup for case 0 or 2
214         //temp points to the new child
215
216         if (stored!=1) {
217
218           //Have to make sure that none of the nodes under this one
219           //are children of the new node
220
221           Iterator iterate2=treenode.children.iterator();
222           temp.parent=treenode;
223
224           //Loop through the children
225           while (iterate2.hasNext()) {
226             Loop temp2=(Loop)iterate2.next();
227
228             //Don't look at the new node...otherwise we will create
229             //a unreachable subtree
230
231             if (temp2!=temp)
232               //If the new node has a childs header
233               //give the child up to it...
234
235               if (temp.entries.contains(temp2.header)) {
236                 temp.children.add(temp2);
237                 iterate2.remove();
238               }
239           }
240         }
241
242         //We fixed everything...let our parents know
243         return 1;
244       } else {
245         //need to combine loops
246         while (!A.entries.isEmpty()) {
247           FlatNode node=(FlatNode)A.entries.iterator().next();
248           A.entries.remove(node);
249           treenode.entries.add(node);
250         }
251         //let the previous caller know that they have stuff todo
252         return 2;
253       }
254     //We aren't adopting the new node
255     else return 0;
256   }
257
258   void findloopheaders(FlatNode current_nodeOrig) {
259     Stack stk = new Stack();
260     stk.push(current_nodeOrig);
261     while( !stk.isEmpty() ) {
262       FlatNode current_node = (FlatNode) stk.pop();
263       //look at the current node
264       visit(current_node);
265
266       //add it to the all inclusive root loop
267       root.entries.add(current_node);
268
269       //See if those we dominate are backedges
270       Set<FlatNode> children=dominator.children(current_node);
271
272       if (children!=null) {
273         for(Iterator<FlatNode> it=children.iterator(); it.hasNext(); ) {
274           FlatNode fn=it.next();
275           if (fn!=current_node)
276             stk.push(fn);
277         }
278       }
279     }
280   }
281
282   void visit(FlatNode q) {
283     Loop A=new Loop();
284     HashSet B=new HashSet();
285
286     //Loop through all of our outgoing edges
287     for (int i=0; i<q.numNext(); i++) {
288       FlatNode temp=q;
289       FlatNode temp_to=q.getNext(i);
290
291       //Go up the dominator tree until
292       //we hit the root element or we
293       //find the node we jump back too
294       while ((temp!=hc)&&
295              (temp_to!=temp)) {
296         temp=dominator.idom(temp);
297       }
298
299       //If we found the node we jumped back to
300       //then build loop
301
302       if (temp_to==temp) {
303
304         //found a loop
305         A.entries.add(temp); //Push the header
306         A.header=temp;
307         B.add(q); //Put the backedge in the todo list
308
309         //Starting with the backedge, work on the incoming edges
310         //until we get back to the loop header...
311         //Then we have the entire natural loop
312
313         while(!B.isEmpty()) {
314           FlatNode newnode=(FlatNode)B.iterator().next();
315           B.remove(newnode);
316
317           //Add all of the new incoming edges that we haven't already
318           //visited
319           for (int j=0; j<newnode.numPrev(); j++) {
320             FlatNode from=newnode.getPrev(j);
321             if (!A.entries.contains(from))
322               B.add(from);
323           }
324
325           //push the new node on our list of nodes in the loop
326           A.entries.add(newnode);
327         }
328
329         //save our new loop
330         setofloops.add(A);
331       }
332     }
333   }
334
335   //Structure for building internal trees...
336
337   class Loop {
338     public HashSet entries=new HashSet();
339     public FlatNode header;
340     //Elements of the WorkSet of children are
341     //of the type Loop
342     public HashSet children=new HashSet();
343     public Loop parent;
344   }
345 }