1 cananian 1.1.2.1 // SESE.java, created Mon Mar 1 23:52:29 1999 by cananian 2 cananian 1.1.2.1 // Copyright (C) 1999 C. Scott Ananian <cananian@alumni.princeton.edu> 3 cananian 1.1.2.1 // Licensed under the terms of the GNU GPL; see COPYING for details. 4 cananian 1.1.2.1 package harpoon.Analysis; 5 cananian 1.1.2.1 6 cananian 1.1.2.2 import harpoon.ClassFile.HCode; 7 cananian 1.1.2.2 import harpoon.ClassFile.HCodeEdge; 8 cananian 1.1.2.2 import harpoon.ClassFile.HCodeElement; 9 cananian 1.6 import net.cscott.jutil.UnmodifiableIterator; 10 cananian 1.1.2.1 import harpoon.Util.Util; 11 cananian 1.1.2.1 12 cananian 1.1.2.1 import java.util.AbstractSet; 13 cananian 1.1.2.4 import java.util.ArrayList; 14 cananian 1.1.2.4 import java.util.Collection; 15 cananian 1.1.2.2 import java.util.Collections; 16 cananian 1.1.2.1 import java.util.HashMap; 17 cananian 1.1.2.1 import java.util.HashSet; 18 cananian 1.1.2.1 import java.util.Iterator; 19 cananian 1.1.2.1 import java.util.LinkedList; 20 cananian 1.1.2.1 import java.util.List; 21 cananian 1.1.2.1 import java.util.ListIterator; 22 cananian 1.1.2.1 import java.util.Map; 23 cananian 1.1.2.1 import java.util.Set; 24 cananian 1.1.2.2 import java.util.Stack; 25 cananian 1.1.2.1 26 cananian 1.1.2.1 /** 27 cananian 1.1.2.1 * <code>SESE</code> computes nested single-entry single-exit regions 28 cananian 1.1.2.12 * from a cycle-equivalency set.<p> 29 cananian 1.1.2.12 * See Johnson, Pearson, and Pingali, <A 30 cananian 1.1.2.12 * HREF="http://cs-tr.cs.cornell.edu:80/Dienst/UI/1.0/Display/ncstrl.cornell/TR93-1365" 31 cananian 1.1.2.12 * >"Finding regions fast: Single entry single exit and control regions in 32 cananian 1.1.2.12 * linear time"</A> (Technical Report TR 93-1365, Cornell University, 33 cananian 1.1.2.12 * July 1993). Their PLDI'94 paper "The program structure tree: Computing 34 cananian 1.1.2.12 * control regions in linear time" might also provide a useful reference. 35 cananian 1.1.2.1 * 36 cananian 1.1.2.1 * @author C. Scott Ananian <cananian@alumni.princeton.edu> 37 cananian 1.7 * @version $Id: SESE.java,v 1.7 2004/02/08 03:19:12 cananian Exp $ 38 cananian 1.1.2.1 */ 39 cananian 1.1.2.1 public class SESE { 40 cananian 1.1.2.2 /** Root of <code>Region</code> tree. */ 41 cananian 1.1.2.2 public final Region topLevel=new Region(); 42 cananian 1.1.2.2 /** Mapping from Nodes/Edges to smallest enclosing canonical SESE 43 cananian 1.1.2.2 * <code>Region</code>. */ 44 cananian 1.3.2.2 public final Map smallestSESE; 45 cananian 1.1.2.1 46 cananian 1.1.2.5 /** Creates a <code>SESE</code> using a <code>CycleEq</code>. */ 47 sportbilly 1.1.2.9 public SESE(HCode hc) { 48 cananian 1.1.2.2 // compute cycle equivalence. 49 sportbilly 1.1.2.9 CycleEq ceq = new CycleEq(hc); 50 cananian 1.1.2.2 // use cycle equivalence classes to determine canonical sese regions. 51 cananian 1.1.2.1 Map entryRegion= new HashMap(); 52 cananian 1.1.2.1 Map exitRegion = new HashMap(); 53 cananian 1.7 for (Object lO : ceq.cdClasses()) { 54 cananian 1.7 List l = (List) lO; 55 cananian 1.1.2.1 Object prev=null; 56 cananian 1.1.2.1 for (Iterator lit=l.listIterator(); lit.hasNext(); ) { 57 cananian 1.1.2.1 Object o = lit.next(); 58 cananian 1.1.2.1 if (prev!=null) { 59 cananian 1.1.2.1 Region r = new Region(prev, o); 60 cananian 1.1.2.1 entryRegion.put(prev, r); 61 cananian 1.1.2.1 exitRegion.put(o, r); 62 cananian 1.1.2.1 } 63 cananian 1.1.2.1 prev = o; 64 cananian 1.1.2.1 } 65 cananian 1.1.2.1 } 66 cananian 1.1.2.2 // now do DFS traversal of CFG to determine nesting of regions. 67 cananian 1.1.2.2 Map workSmallSESE = new HashMap(); 68 cananian 1.1.2.2 // state for DFS 69 cananian 1.1.2.2 Set visited = new HashSet(); visited.add(hc.getRootElement()); 70 cananian 1.1.2.2 Stack nodeS = new Stack(); nodeS.push(hc.getRootElement()); 71 cananian 1.1.2.2 Stack regionS=new Stack(); regionS.push(topLevel); 72 cananian 1.1.2.2 73 cananian 1.1.2.2 while (!nodeS.isEmpty()) { 74 cananian 1.3.2.1 assert nodeS.size()==regionS.size(); 75 cananian 1.1.2.2 Object o = nodeS.pop(); // either an HCodeElement or an HCodeEdge 76 cananian 1.1.2.2 Region cR= (Region) regionS.pop(); // currentRegion. 77 cananian 1.1.2.2 // deal with region entry/exit. 78 sportbilly 1.1.2.9 if (true==(o instanceof HCodeElement)) { 79 cananian 1.1.2.4 // cR is smallest enclosing canonical SESE of o. 80 cananian 1.1.2.4 workSmallSESE.put(o, cR); 81 cananian 1.1.2.4 cR.nodes.add(o); 82 cananian 1.1.2.2 } else { // update current region. 83 cananian 1.1.2.2 // if this is found in the cycle-equivalency stuff, push/pop. 84 cananian 1.1.2.2 Region r1 = (Region) entryRegion.get(o); 85 cananian 1.1.2.2 Region r2 = (Region) exitRegion.get(o); 86 cananian 1.1.2.2 // pop up one level if we are leaving the region. 87 cananian 1.1.2.2 if (cR.equals(r1)) { cR=cR.parent; r1=null; } 88 cananian 1.1.2.2 if (cR.equals(r2)) { cR=cR.parent; r2=null; } 89 cananian 1.1.2.2 // push a level if we are entering the region. 90 cananian 1.1.2.2 if (r1!=null) { Region.link(cR, r1); cR=r1; } 91 cananian 1.1.2.2 if (r2!=null) { Region.link(cR, r2); cR=r2; } 92 cananian 1.1.2.1 } 93 cananian 1.1.2.2 // continue DFS traversal. 94 cananian 1.1.2.2 Object[] succ=null; 95 cananian 1.1.2.2 if (o instanceof HCodeElement) // Node. Push edges. 96 cananian 1.1.2.10 succ = ((harpoon.IR.Properties.CFGraphable)o).succ(); 97 cananian 1.1.2.2 if (o instanceof HCodeEdge) // Edge. Push node. 98 cananian 1.1.2.2 succ = new HCodeElement[] { ((HCodeEdge)o).to() }; 99 cananian 1.1.2.2 for (int i=succ.length-1; i>=0; i--) 100 cananian 1.1.2.2 if (!visited.contains(succ[i])) { 101 cananian 1.1.2.2 nodeS.push(succ[i]); regionS.push(cR); 102 cananian 1.1.2.2 visited.add(succ[i]); 103 cananian 1.1.2.2 } 104 cananian 1.1.2.2 } // END while. 105 cananian 1.3.2.1 assert nodeS.isEmpty() && regionS.isEmpty(); 106 cananian 1.1.2.2 // make smallestSESE map unmodifiable. 107 cananian 1.1.2.2 smallestSESE = Collections.unmodifiableMap(workSmallSESE); 108 cananian 1.1.2.4 // make region lists unmodifiable 109 cananian 1.1.2.4 for (Iterator it = topDown(); it.hasNext(); ) { 110 cananian 1.1.2.4 Region r = (Region) it.next(); 111 cananian 1.1.2.4 r.nodes = Collections.unmodifiableCollection(r.nodes); 112 cananian 1.1.2.4 } 113 cananian 1.1.2.1 } 114 cananian 1.1.2.1 115 cananian 1.1.2.2 /** Iterate through SESE regions, top-down. All top-level regions 116 cananian 1.1.2.2 * are visited first, then all children of top-level regions, then 117 cananian 1.1.2.2 * all grandchildren, then all great-grandchildren, etc. */ 118 cananian 1.1.2.4 public Iterator topDown() { return iterator(true); } 119 cananian 1.1.2.4 /** Iterate through SESE regions, depth-first. */ 120 cananian 1.1.2.4 public Iterator depthFirst() { return iterator(false); } 121 cananian 1.1.2.4 122 cananian 1.1.2.4 private Iterator iterator(final boolean topdown) { 123 cananian 1.1.2.7 return new UnmodifiableIterator() { 124 cananian 1.1.2.1 LinkedList ll = new LinkedList(); 125 cananian 1.1.2.2 { ll.add(topLevel); } 126 cananian 1.1.2.1 public boolean hasNext() { return !ll.isEmpty(); } 127 cananian 1.1.2.1 public Object next() { 128 cananian 1.1.2.4 Region r = (Region) (topdown?ll.removeFirst():ll.removeLast()); 129 cananian 1.1.2.1 ll.addAll(r.children()); 130 cananian 1.1.2.1 return r; 131 cananian 1.1.2.1 } 132 cananian 1.1.2.1 }; 133 cananian 1.1.2.1 } 134 cananian 1.1.2.1 135 cananian 1.1.2.1 public void print(java.io.PrintWriter pw) { 136 cananian 1.1.2.4 for (Iterator it=depthFirst(); it.hasNext(); ) { 137 cananian 1.1.2.1 Region r = (Region) it.next(); 138 cananian 1.1.2.4 for (int i=0; i<r.level; i++) 139 cananian 1.1.2.4 pw.print(' '); 140 cananian 1.1.2.4 pw.print(r.toString()); // print region. 141 cananian 1.1.2.4 pw.print(" : "); 142 cananian 1.1.2.4 pw.println(r.nodes.toString()); // print members 143 cananian 1.1.2.1 } 144 cananian 1.1.2.2 } 145 cananian 1.1.2.1 146 cananian 1.1.2.11 /** <code>SESE.Region</code> represents a single-entry single-exit 147 cananian 1.1.2.11 * (SESE) Region, as computed by the <code>SESE</code> object. */ 148 cananian 1.1.2.1 public static class Region { 149 cananian 1.1.2.11 /** entry edge of the region. */ 150 cananian 1.1.2.11 public final Object entry; 151 cananian 1.1.2.11 /** exit edge of the region. */ 152 cananian 1.1.2.11 public final Object exit; 153 cananian 1.1.2.1 // tree info. 154 cananian 1.1.2.4 int level=0; 155 cananian 1.1.2.1 Region parent=null; 156 cananian 1.1.2.1 RegionList children=null; 157 cananian 1.1.2.4 // list of nodes in this region 158 cananian 1.1.2.4 Collection nodes = new ArrayList(); 159 cananian 1.1.2.1 160 cananian 1.1.2.1 Region() { // create top-level region. 161 cananian 1.1.2.1 this.entry = this.exit = null; 162 cananian 1.3.2.1 assert isTopLevel(); 163 cananian 1.1.2.1 } 164 cananian 1.1.2.1 Region(Object entry, Object exit) { 165 cananian 1.1.2.1 this.entry = entry; this.exit = exit; 166 cananian 1.3.2.1 assert !isTopLevel(); 167 cananian 1.1.2.1 } 168 cananian 1.1.2.1 169 cananian 1.1.2.11 /** Parent region of this one (<code>null</code> for top-level 170 cananian 1.1.2.11 * region). */ 171 cananian 1.1.2.1 public Region parent() { return this.parent; } 172 cananian 1.1.2.11 /** Child regions of this one. */ 173 cananian 1.1.2.1 public Set children() { return RegionList.asSet(this.children); } 174 cananian 1.1.2.11 /** Nodes in this region (and not contained in any child regions) */ 175 cananian 1.1.2.4 public Collection nodes() { return this.nodes; } 176 cananian 1.1.2.1 177 cananian 1.1.2.1 boolean isTopLevel() { 178 cananian 1.1.2.1 return (this.entry==null) && (this.exit==null); 179 cananian 1.1.2.1 } 180 cananian 1.1.2.11 /** Compare two regions for equality. */ 181 cananian 1.1.2.1 public boolean equals(Object o) { 182 cananian 1.1.2.8 Region r; 183 cananian 1.1.2.8 if (this==o) return true; 184 cananian 1.1.2.8 if (o==null) return false; 185 cananian 1.1.2.8 try { r=(Region)o; } 186 cananian 1.1.2.8 catch (ClassCastException e) { return false; } 187 cananian 1.1.2.8 if (isTopLevel()) return r.isTopLevel(); 188 cananian 1.1.2.1 else return 189 cananian 1.1.2.8 this.entry.equals(r.entry) && 190 cananian 1.1.2.8 this.exit.equals(r.exit); 191 cananian 1.1.2.1 } 192 cananian 1.1.2.1 public int hashCode() { 193 cananian 1.1.2.1 if (isTopLevel()) return 0; 194 cananian 1.1.2.1 else return (entry.hashCode()<<7) ^ exit.hashCode(); 195 cananian 1.1.2.1 } 196 cananian 1.1.2.1 public String toString() { 197 cananian 1.1.2.1 if (isTopLevel()) return "[-toplevel-]"; 198 cananian 1.1.2.1 else return "["+entry+"->"+exit+"]"; 199 cananian 1.1.2.1 } 200 cananian 1.1.2.1 static void link(Region parent, Region child) { 201 cananian 1.1.2.4 child.level = 1 + parent.level; 202 cananian 1.1.2.1 child.parent = parent; 203 cananian 1.1.2.1 parent.children = new RegionList(child, parent.children); 204 cananian 1.1.2.1 } 205 cananian 1.1.2.1 } 206 cananian 1.1.2.1 static class RegionList { 207 cananian 1.1.2.1 final Region region; 208 cananian 1.1.2.1 final RegionList next; 209 cananian 1.1.2.1 final int size; 210 cananian 1.1.2.1 RegionList(Region region, RegionList next) { 211 cananian 1.1.2.1 this.region = region; this.next = next; 212 cananian 1.1.2.1 this.size = 1+((next==null)?0:next.size); 213 cananian 1.1.2.1 } 214 cananian 1.1.2.1 static Iterator elements(final RegionList rl) { 215 cananian 1.1.2.7 return new UnmodifiableIterator() { 216 cananian 1.1.2.1 RegionList rlp = rl; 217 cananian 1.1.2.1 public boolean hasNext() { return rlp!=null; } 218 cananian 1.1.2.1 public Object next() { 219 cananian 1.1.2.1 Region r = rlp.region; rlp=rlp.next; return r; 220 cananian 1.1.2.1 } 221 cananian 1.1.2.1 }; 222 cananian 1.1.2.1 } 223 cananian 1.1.2.1 static Set asSet(final RegionList rl) { 224 cananian 1.1.2.1 return new AbstractSet() { 225 cananian 1.1.2.1 public boolean isEmpty() { return rl==null; } 226 cananian 1.1.2.1 public int size() { return (rl==null)?0:rl.size; } 227 cananian 1.1.2.1 public Iterator iterator() { return elements(rl); } 228 cananian 1.1.2.1 }; 229 cananian 1.1.2.1 } 230 cananian 1.1.2.1 } 231 cananian 1.2 }