1 pnkfelix 1.1.2.1 // InstrGroup.java, created Fri Jan  5 11:25:20 2001 by pnkfelix
  2 cananian 1.1.2.4 // Copyright (C) 2000 Felix S. Klock II <pnkfelix@mit.edu>
  3 pnkfelix 1.1.2.1 // Licensed under the terms of the GNU GPL; see COPYING for details.
  4 pnkfelix 1.1.2.1 package harpoon.IR.Assem;
  5 pnkfelix 1.1.2.1 
  6 pnkfelix 1.1.2.1 import harpoon.ClassFile.HCode;
  7 cananian 1.3.2.2 import harpoon.ClassFile.HCodeEdge;
  8 pnkfelix 1.1.2.1 import harpoon.ClassFile.HCodeElement;
  9 pnkfelix 1.1.2.1 import harpoon.IR.Properties.CFGEdge;
 10 pnkfelix 1.1.2.1 import harpoon.IR.Properties.CFGrapher;
 11 pnkfelix 1.1.2.1 import harpoon.IR.Properties.CFGraphable;
 12 pnkfelix 1.1.2.1 import harpoon.IR.Properties.UseDefer;
 13 pnkfelix 1.1.2.1 import harpoon.IR.Properties.UseDefable;
 14 cananian 1.3.2.2 import harpoon.Temp.Temp;
 15 cananian 1.6     import net.cscott.jutil.Default;
 16 pnkfelix 1.1.2.1 import harpoon.Util.Util;
 17 pnkfelix 1.1.2.1 
 18 cananian 1.5     import java.util.AbstractList;
 19 cananian 1.3.2.2 import java.util.Arrays;
 20 pnkfelix 1.1.2.1 import java.util.Collection;
 21 pnkfelix 1.1.2.3 import java.util.Collections;
 22 pnkfelix 1.1.2.1 import java.util.HashMap;
 23 pnkfelix 1.1.2.1 import java.util.HashSet;
 24 cananian 1.5     import java.util.List;
 25 cananian 1.3.2.2 import java.util.Map;
 26 pnkfelix 1.1.2.1 /**
 27 pnkfelix 1.1.2.1  * <code>InstrGroup</code> collects a group of assembly instructions
 28 pnkfelix 1.1.2.1  * together so that they can be viewed as a single atomic element of
 29 pnkfelix 1.1.2.1  * the code.  This allows for differing levels of abstraction as
 30 pnkfelix 1.1.2.1  * required by various compiler passes.  Each set of instructions
 31 pnkfelix 1.1.2.1  * collected by an <code>InstrGroup</code> must collectively form a
 32 pnkfelix 1.1.2.1  * single-entry single-exit region.
 33 pnkfelix 1.1.2.8  *
 34 cananian 1.1.2.4  * @author  Felix S. Klock II <pnkfelix@mit.edu>
 35 cananian 1.6      * @version $Id: InstrGroup.java,v 1.6 2004/02/08 01:55:08 cananian Exp $ */
 36 pnkfelix 1.1.2.1 public class InstrGroup {
 37 pnkfelix 1.1.2.1     Type type;
 38 pnkfelix 1.1.2.1     Instr entry, exit;
 39 pnkfelix 1.1.2.1     InstrGroup containedIn; // null ==> not contained in supergroup 
 40 pnkfelix 1.1.2.1 
 41 pnkfelix 1.1.2.1     /** Creates a <code>InstrGroup</code>. */
 42 pnkfelix 1.1.2.1     public InstrGroup(Type type) {
 43 pnkfelix 1.1.2.1         this.type = type;
 44 pnkfelix 1.1.2.1         containedIn = null;
 45 pnkfelix 1.1.2.1     }
 46 pnkfelix 1.1.2.1 
 47 pnkfelix 1.1.2.1     /** Creates a <code>InstrGroup</code> contained in
 48 pnkfelix 1.1.2.1         <code>contained</code>. 
 49 pnkfelix 1.1.2.1     */
 50 pnkfelix 1.1.2.1     public InstrGroup(Type type, InstrGroup container) {
 51 pnkfelix 1.1.2.1         this.type = type;
 52 pnkfelix 1.1.2.1         containedIn = container;
 53 pnkfelix 1.1.2.1     }
 54 pnkfelix 1.1.2.1     
 55 pnkfelix 1.1.2.1     public String toString() { 
 56 pnkfelix 1.1.2.3         return "<group type:"+type.typeString+
 57 pnkfelix 1.1.2.3             ",entry:"+((entry==null)?"null":""+entry.getID())+
 58 pnkfelix 1.1.2.3             ",exit:"+((exit==null)?"null":""+exit.getID())+">";
 59 pnkfelix 1.1.2.1     }
 60 pnkfelix 1.1.2.1 
 61 pnkfelix 1.1.2.1     /** Returns true if this is contained in a super group, else
 62 pnkfelix 1.1.2.1         false. 
 63 pnkfelix 1.1.2.1     */
 64 pnkfelix 1.1.2.1     public boolean hasContainer() { return containedIn != null; }
 65 pnkfelix 1.1.2.1 
 66 pnkfelix 1.1.2.1     /** Returns the <code>InstrGroup</code> containing
 67 pnkfelix 1.1.2.1         <code>this</code>, or <code>null</code> if this is not
 68 pnkfelix 1.1.2.1         contained in any super group.
 69 pnkfelix 1.1.2.1     */
 70 pnkfelix 1.1.2.1     public InstrGroup getContainer() { return containedIn; }
 71 pnkfelix 1.1.2.1 
 72 pnkfelix 1.1.2.3     /** Returns true if this is (reflexively) contained in
 73 pnkfelix 1.1.2.3         <code>group</code>.  */
 74 pnkfelix 1.1.2.3     public boolean subgroupOf(InstrGroup group) {
 75 pnkfelix 1.1.2.3         return (group != null) && 
 76 pnkfelix 1.1.2.3             (this == group || 
 77 pnkfelix 1.1.2.3              this.containedIn == group || 
 78 pnkfelix 1.1.2.3              (containedIn != null && 
 79 pnkfelix 1.1.2.3               containedIn.subgroupOf( group )));
 80 pnkfelix 1.1.2.3     }
 81 pnkfelix 1.1.2.3 
 82 pnkfelix 1.1.2.1     /** Sets the entry point for a group of instructions.  Should be
 83 pnkfelix 1.1.2.1         called once (and only once), before setExit is called.  */
 84 pnkfelix 1.1.2.1     public void setEntry(Instr entry) { 
 85 cananian 1.3.2.1         assert this.entry == null;
 86 pnkfelix 1.1.2.1         this.entry = entry; 
 87 pnkfelix 1.1.2.1     }
 88 pnkfelix 1.1.2.1     /** Sets the exit point for this group of instructions.  Should be
 89 pnkfelix 1.1.2.1         called once (and only once).  Note that
 90 pnkfelix 1.1.2.1         for a given InstrGroup(fact, a), after setExit(b) has been
 91 pnkfelix 1.1.2.1         called, it should be the case for the code associated with
 92 pnkfelix 1.1.2.1         <code>fact</code>: <UL>
 93 pnkfelix 1.1.2.1         <LI> a dominates b
 94 pnkfelix 1.1.2.1         <LI> b postdominates a
 95 pnkfelix 1.1.2.1         <LI> a and b are cycle-equivalent</UL>.  */
 96 pnkfelix 1.1.2.1     public void setExit(Instr exit) { 
 97 cananian 1.3.2.1         assert this.exit == null;
 98 pnkfelix 1.1.2.1         this.exit = exit; 
 99 pnkfelix 1.1.2.1     }
100 pnkfelix 1.1.2.1 
101 pnkfelix 1.1.2.1     /** <code>InstrGroup.GroupGrapher</code> turns an Instr -> Group map
102 pnkfelix 1.1.2.1         into a <code>CFGrapher</code>.  The predecessor and successor
103 pnkfelix 1.1.2.1         relations in <code>InstrGroup.Grapher</code> use the groups to
104 pnkfelix 1.1.2.1         abstract away the control flow and layout dictated by the
105 pnkfelix 1.1.2.1         Instrs internally, returning the entry points of each group
106 pnkfelix 1.1.2.1         when needed.  */
107 cananian 1.3.2.2     static class GroupGrapher extends CFGrapher<Instr> {
108 cananian 1.3.2.2         private Map<Instr,InstrGroup> i2g;
109 pnkfelix 1.1.2.1 
110 cananian 1.3.2.2         GroupGrapher(Map<Instr,InstrGroup> instrToGroup) { // local to Assem package
111 pnkfelix 1.1.2.1             i2g = instrToGroup;
112 pnkfelix 1.1.2.1         }
113 pnkfelix 1.1.2.1 
114 cananian 1.3.2.2         public Instr[] getLastElements(HCode<Instr> hcode) { 
115 pnkfelix 1.1.2.6             // FSK: is this even necessary?  It was w/o exit mapping,
116 pnkfelix 1.1.2.6             // but w/ exit mapping, I think that this loop is just an
117 pnkfelix 1.1.2.6             // identity transform.  Should look into it later.
118 cananian 1.3.2.2             Instr[] hces = hcode.getLeafElements();
119 pnkfelix 1.1.2.1             if (hces != null) { // null allowed?  has been so far...
120 pnkfelix 1.1.2.1                 for(int i=0; i<hces.length; i++) {
121 cananian 1.3.2.2                     InstrGroup ig = i2g.get(hces[i]);
122 pnkfelix 1.1.2.1                     if (ig != null)
123 pnkfelix 1.1.2.5                         hces[i] = ig.exit;
124 pnkfelix 1.1.2.1                 }
125 pnkfelix 1.1.2.1             }
126 pnkfelix 1.1.2.1             return hces;
127 pnkfelix 1.1.2.1         }
128 cananian 1.3.2.2         public Instr getFirstElement(HCode<Instr> hcode) { 
129 pnkfelix 1.1.2.1             return hcode.getRootElement();
130 pnkfelix 1.1.2.1         }
131 pnkfelix 1.1.2.1 
132 cananian 1.5             public List<HCodeEdge<Instr>> predC(Instr i) {
133 cananian 1.5                 if (!i2g.containsKey(i)) {
134 cananian 1.6                     return Collections.<HCodeEdge<Instr>>unmodifiableList
135 cananian 1.6                         (i.predC());
136 pnkfelix 1.1.2.5             } else {
137 cananian 1.3.2.2                 InstrGroup ig = i2g.get(i);
138 pnkfelix 1.1.2.5                 if (i == ig.exit) {
139 cananian 1.6                         return Collections.<HCodeEdge<Instr>>singletonList
140 cananian 1.6                             (new InstrEdge(ig.entry, ig.exit));
141 pnkfelix 1.1.2.5                 } else {
142 cananian 1.3.2.1                     assert i == ig.entry;
143 cananian 1.6                         return Collections.<HCodeEdge<Instr>>unmodifiableList
144 cananian 1.6                             (i.predC());
145 pnkfelix 1.1.2.1                 }
146 pnkfelix 1.1.2.1             }
147 pnkfelix 1.1.2.1         }
148 pnkfelix 1.1.2.1 
149 cananian 1.5             public List<HCodeEdge<Instr>> succC(Instr i) { 
150 pnkfelix 1.1.2.1             if (!i2g.containsKey(i)) {
151 cananian 1.6                     return Collections.<HCodeEdge<Instr>>unmodifiableList
152 cananian 1.6                         (i.succC());
153 pnkfelix 1.1.2.1             } else {
154 cananian 1.3.2.2                 InstrGroup ig = i2g.get(i);
155 pnkfelix 1.1.2.5                 if (i == ig.entry) {
156 cananian 1.6                         return Collections.<HCodeEdge<Instr>>singletonList
157 cananian 1.6                             (new InstrEdge(ig.entry, ig.exit));
158 pnkfelix 1.1.2.5                 } else {
159 cananian 1.3.2.1                     assert i == ig.exit;
160 cananian 1.6                         return Collections.<HCodeEdge<Instr>>unmodifiableList
161 cananian 1.6                             (i.succC());
162 pnkfelix 1.1.2.1                 }
163 pnkfelix 1.1.2.1             }
164 pnkfelix 1.1.2.1         }
165 pnkfelix 1.1.2.1     }
166 pnkfelix 1.1.2.1     /** <code>InstrGroup.GroupUseDefer</code> turns an Instr -> Group
167 pnkfelix 1.1.2.1         map into a <code>UseDefer</code>.  It does this by performing
168 pnkfelix 1.1.2.1         a reverse data-flow analysis, accumulating definitions, along
169 pnkfelix 1.1.2.1         with uses that have definitions originating <i>outside</i> of
170 pnkfelix 1.1.2.1         the group.  
171 pnkfelix 1.1.2.8         <p>
172 pnkfelix 1.1.2.8         The produced <code>UseDefer</code> then maps all of the temps
173 pnkfelix 1.1.2.8         used by the set of instrs: (group \ {entry}) as coming from
174 pnkfelix 1.1.2.8         the exit of the group, and all of the temps defined by the
175 pnkfelix 1.1.2.8         entire group as coming from the entry of the group.  This is a
176 pnkfelix 1.1.2.8         conservative view; it ensures that the resulting register
177 pnkfelix 1.1.2.8         assignments will be distinct, even when they sometimes did not
178 pnkfelix 1.1.2.8         need to be.
179 pnkfelix 1.1.2.1     */
180 cananian 1.3.2.2     static class GroupUseDefer extends UseDefer<Instr> {
181 cananian 1.3.2.2         private Map<Instr,InstrGroup> i2g;
182 pnkfelix 1.1.2.1         private Type t;
183 cananian 1.3.2.2         GroupUseDefer(Map<Instr,InstrGroup> instrToGroup, Type t) { // local to Assem package
184 pnkfelix 1.1.2.1             i2g = instrToGroup;
185 pnkfelix 1.1.2.1             this.t = t;
186 pnkfelix 1.1.2.1         }
187 pnkfelix 1.1.2.3 
188 pnkfelix 1.1.2.3         // **NOTE** defC and useC are ASYMMETRIC.  
189 cananian 1.3.2.2         public Collection<Temp> useC(Instr i) { 
190 pnkfelix 1.1.2.1             if (!i2g.containsKey(i)) {
191 cananian 1.3.2.1                 assert !i.partOf(t) : ("instr:"+i+" grp type:"+t);
192 pnkfelix 1.1.2.1                 return i.useC();
193 pnkfelix 1.1.2.1             } else {
194 cananian 1.3.2.2                 InstrGroup ig = i2g.get(i);
195 pnkfelix 1.1.2.3                 if(i == ig.entry) {
196 pnkfelix 1.1.2.3                     return i.useC();
197 pnkfelix 1.1.2.3                 }
198 cananian 1.3.2.1                 assert i == ig.exit;
199 pnkfelix 1.1.2.3                 // else work backwards, gathering up uses but killing
200 pnkfelix 1.1.2.3                 // defined uses...
201 pnkfelix 1.1.2.1                 Instr curr = ig.exit;
202 cananian 1.3.2.2                 Collection<Temp> set = new HashSet<Temp>();
203 pnkfelix 1.1.2.1                 do {
204 cananian 1.3.2.1                     assert curr.getGroups().contains(ig);
205 pnkfelix 1.1.2.1                     set.addAll(curr.useC());
206 cananian 1.3.2.1                     assert curr.predC().size() == 1;
207 pnkfelix 1.1.2.1                     curr = (Instr) curr.pred()[0].from();
208 pnkfelix 1.1.2.3                     set.removeAll(curr.defC()); // order here is key
209 pnkfelix 1.1.2.1                 } while(curr != ig.entry);
210 pnkfelix 1.1.2.1 
211 pnkfelix 1.1.2.1                 return set;
212 pnkfelix 1.1.2.1             }
213 pnkfelix 1.1.2.1         }
214 cananian 1.3.2.2         public Collection<Temp> defC(Instr i) { 
215 pnkfelix 1.1.2.1             if (!i2g.containsKey(i)) {
216 cananian 1.3.2.1                 assert !i.partOf(t);
217 pnkfelix 1.1.2.1                 return i.defC();
218 pnkfelix 1.1.2.1             } else {
219 cananian 1.3.2.2                 InstrGroup ig = i2g.get(i);
220 pnkfelix 1.1.2.3                 if (i == ig.exit) {
221 pnkfelix 1.1.2.3                     return Collections.EMPTY_SET;
222 pnkfelix 1.1.2.3                 } 
223 pnkfelix 1.1.2.3                 // else gather up all defs and pass them out
224 cananian 1.3.2.1                 assert i == ig.entry;
225 pnkfelix 1.1.2.1                 Instr curr = ig.exit;
226 pnkfelix 1.1.2.7                 
227 pnkfelix 1.1.2.7                 // start with defs in last instr (shifting them to the
228 pnkfelix 1.1.2.7                 // start of the group)
229 cananian 1.3.2.2                 Collection<Temp> set = new HashSet<Temp>( curr.defC() );
230 pnkfelix 1.1.2.1 
231 pnkfelix 1.1.2.1                 do {
232 cananian 1.3.2.1                     assert curr.getGroups().contains(ig);
233 cananian 1.3.2.1                     assert curr.predC().size() == 1;
234 pnkfelix 1.1.2.1                     curr = (Instr) curr.pred()[0].from();
235 pnkfelix 1.1.2.3                     set.addAll(curr.defC());
236 pnkfelix 1.1.2.1                 } while(curr != ig.entry);
237 pnkfelix 1.1.2.1 
238 pnkfelix 1.1.2.1                 return set;
239 pnkfelix 1.1.2.1             }
240 pnkfelix 1.1.2.1         }
241 pnkfelix 1.1.2.1     }
242 pnkfelix 1.1.2.1 
243 pnkfelix 1.1.2.8     /** <code>InstrGroup.Type</code> is associated with a collection
244 pnkfelix 1.1.2.8         of <code>InstrGroup</code>s for a given
245 pnkfelix 1.1.2.8         <code>Assem.Code</code>.  Each <code>InstrGroup.Type</code> is
246 pnkfelix 1.1.2.8         meant to be used as a way to extract abstract <i>views</i> of
247 pnkfelix 1.1.2.8         the <code>Assem.Code</code>.
248 pnkfelix 1.1.2.8     
249 pnkfelix 1.1.2.8     */
250 pnkfelix 1.1.2.1     public static class Type {
251 pnkfelix 1.1.2.1         private String typeString;
252 pnkfelix 1.1.2.3         private String details;
253 pnkfelix 1.1.2.3         private Type(String groupType, String details) { 
254 pnkfelix 1.1.2.1             typeString = groupType;
255 pnkfelix 1.1.2.3             this.details = details;
256 pnkfelix 1.1.2.1         }
257 pnkfelix 1.1.2.1 
258 pnkfelix 1.1.2.1         /** Creates an <code>InstrGroup</code> of the type for
259 pnkfelix 1.1.2.1             <code>this</code> representing <code>rep</code>.  Note
260 pnkfelix 1.1.2.1             that <code>rep</code> should be the entry point for the
261 pnkfelix 1.1.2.1             group of instructions that will be collected by the
262 pnkfelix 1.1.2.1             returned <code>InstrGroup</code>.  */
263 pnkfelix 1.1.2.1         public InstrGroup makeGroup() {
264 pnkfelix 1.1.2.1             return new InstrGroup(this);
265 pnkfelix 1.1.2.1         }
266 pnkfelix 1.1.2.1         /** Creates an <code>InstrGroup</code>, contained in
267 pnkfelix 1.1.2.1             <code>container</code> of the type for <code>this</code>
268 pnkfelix 1.1.2.1             representing <code>rep</code>.  Note that <code>rep</code>
269 pnkfelix 1.1.2.1             should be the entry point for the group of instructions
270 pnkfelix 1.1.2.1             that will be collected by the returned
271 pnkfelix 1.1.2.1             <code>InstrGroup</code>.  If container is null, then the
272 pnkfelix 1.1.2.1             generated InstrGroup will have no containing group. */
273 pnkfelix 1.1.2.1         public InstrGroup makeGroup(InstrGroup container) {
274 pnkfelix 1.1.2.1             return new InstrGroup(this, container);
275 pnkfelix 1.1.2.1         }
276 pnkfelix 1.1.2.1         
277 pnkfelix 1.1.2.1         public String toString() { 
278 pnkfelix 1.1.2.1             return "InstrGroup.Type:"+typeString; 
279 pnkfelix 1.1.2.1         }
280 pnkfelix 1.1.2.1     }
281 pnkfelix 1.1.2.1 
282 pnkfelix 1.1.2.1     /** groups code such as local labels (1f/1:).
283 pnkfelix 1.1.2.1      */
284 pnkfelix 1.1.2.3     public static Type NO_REORDER=new Type("ord","order sensitive dependencies");
285 pnkfelix 1.1.2.1     
286 pnkfelix 1.1.2.1     /** groups code such as double word moves where we do not want to
287 pnkfelix 1.1.2.1         allow one half of the location to be assigned to hold the 2nd
288 pnkfelix 1.1.2.1         half.
289 pnkfelix 1.1.2.1     */
290 pnkfelix 1.1.2.3     public static Type AGGREGATE=new Type("agg","aggregate instructions");
291 pnkfelix 1.1.2.1 
292 pnkfelix 1.1.2.1     /** groups code where we cannot insert spill code (such as
293 pnkfelix 1.1.2.1         aggregates where spill code would destroy effect of virtual
294 pnkfelix 1.1.2.1         DUMMY instructions added in).  Note that it is legal to insert
295 pnkfelix 1.1.2.1         spill code BEFORE the group, just not between instructions
296 pnkfelix 1.1.2.1         contained within the group.
297 pnkfelix 1.1.2.1     */
298 pnkfelix 1.1.2.3     public static Type NO_SPILL=new Type("!sp","spill sensitive dependencies");
299 pnkfelix 1.1.2.1 
300 pnkfelix 1.1.2.1     /** groups code with special delay slot instructions... (usable?)
301 pnkfelix 1.1.2.1      */
302 pnkfelix 1.1.2.3     public static Type DELAY_SLOT=new Type("del","delay slot");
303 pnkfelix 1.1.2.1     
304 pnkfelix 1.1.2.1 }
305 pnkfelix 1.1.2.1 
306 cananian 1.2