1 kkz      1.1.2.18 // ConstantPropagation.java, created Fri Aug 24 22:57:03 2001 by kkz
  2 kkz      1.1.2.18 // Copyright (C) 2000 Karen Zee <kkz@tmi.lcs.mit.edu>
  3 cananian 1.1.2.7  // Licensed under the terms of the GNU GPL; see COPYING for details.
  4 duncan   1.1.2.1  package harpoon.Analysis.Tree;
  5 duncan   1.1.2.1  
  6 kkz      1.1.2.18 import harpoon.Analysis.ReachingDefs;
  7 kkz      1.1.2.18 import harpoon.Analysis.ReachingDefsAltImpl;
  8 kkz      1.1.2.18 import harpoon.Analysis.ReachingDefsImpl;
  9 kkz      1.1.2.18 import harpoon.ClassFile.HCodeAndMaps;
 10 kkz      1.1.2.18 import harpoon.ClassFile.HCode;
 11 kkz      1.1.2.18 import harpoon.ClassFile.HCodeFactory;
 12 pnkfelix 1.1.2.5  import harpoon.IR.Properties.CFGrapher;
 13 cananian 1.1.2.14 import harpoon.IR.Properties.UseDefer;
 14 kkz      1.1.2.18 import harpoon.IR.Tree.ALIGN;
 15 kkz      1.1.2.18 import harpoon.IR.Tree.BINOP;
 16 kkz      1.1.2.18 import harpoon.IR.Tree.CJUMP;
 17 duncan   1.1.2.1  import harpoon.IR.Tree.CONST;
 18 kkz      1.1.2.18 import harpoon.IR.Tree.CanonicalTreeCode;
 19 kkz      1.1.2.18 import harpoon.IR.Tree.Code;
 20 kkz      1.1.2.18 import harpoon.IR.Tree.DATUM;
 21 kkz      1.1.2.18 import harpoon.IR.Tree.EXPR;
 22 kkz      1.1.2.18 import harpoon.IR.Tree.Exp;
 23 kkz      1.1.2.18 import harpoon.IR.Tree.ExpList;
 24 kkz      1.1.2.18 import harpoon.IR.Tree.INVOCATION;
 25 kkz      1.1.2.18 import harpoon.IR.Tree.JUMP;
 26 kkz      1.1.2.18 import harpoon.IR.Tree.LABEL;
 27 kkz      1.1.2.18 import harpoon.IR.Tree.MEM;
 28 kkz      1.1.2.18 import harpoon.IR.Tree.METHOD;
 29 kkz      1.1.2.18 import harpoon.IR.Tree.MOVE;
 30 kkz      1.1.2.18 import harpoon.IR.Tree.NAME;
 31 kkz      1.1.2.18 import harpoon.IR.Tree.Print;
 32 kkz      1.1.2.18 import harpoon.IR.Tree.RETURN;
 33 kkz      1.1.2.18 import harpoon.IR.Tree.SEGMENT;
 34 duncan   1.1.2.1  import harpoon.IR.Tree.Stm;
 35 kkz      1.1.2.18 import harpoon.IR.Tree.TEMP;
 36 kkz      1.1.2.18 import harpoon.IR.Tree.THROW;
 37 duncan   1.1.2.1  import harpoon.IR.Tree.Tree;
 38 duncan   1.1.2.1  import harpoon.IR.Tree.TreeKind;
 39 kkz      1.1.2.18 import harpoon.IR.Tree.TreeVisitor;
 40 kkz      1.1.2.18 import harpoon.IR.Tree.UNOP;
 41 kkz      1.1.2.18 import harpoon.Temp.Temp;
 42 duncan   1.1.2.1  import harpoon.Util.Util;
 43 duncan   1.1.2.1  
 44 kkz      1.1.2.18 import java.util.Iterator;
 45 kkz      1.1.2.18 import java.util.Set;
 46 duncan   1.1.2.1  
 47 duncan   1.1.2.1  /**
 48 kkz      1.1.2.18  * <code>ConstantPropagation</code> performs constant
 49 kkz      1.1.2.18  * propagation on canonical tree form.
 50 duncan   1.1.2.1   * 
 51 kkz      1.1.2.18  * @author  Karen Zee <kkz@tmi.lcs.mit.edu>
 52 cananian 1.4       * @version $Id: ConstantPropagation.java,v 1.4 2002/04/10 03:02:06 cananian Exp $
 53 duncan   1.1.2.1   */
 54 kkz      1.1.2.18 public class ConstantPropagation extends 
 55 kkz      1.1.2.18     harpoon.Analysis.Transformation.MethodMutator {
 56 kkz      1.1.2.18     
 57 kkz      1.1.2.18     /** Creates a <code>ConstantPropagation</code>. */
 58 kkz      1.1.2.18     public ConstantPropagation(HCodeFactory parent) { 
 59 kkz      1.1.2.18         super(parent);
 60 cananian 1.3.2.1          assert parent.getCodeName().equals(CanonicalTreeCode.codename);
 61 kkz      1.1.2.18     }
 62 duncan   1.1.2.1  
 63 kkz      1.1.2.18     protected HCode mutateHCode(HCodeAndMaps input) {
 64 kkz      1.1.2.18         Code hc = (Code) input.hcode();
 65 kkz      1.1.2.18         String old = Print.print((Tree)hc.getRootElement());
 66 kkz      1.1.2.18         CFGrapher cfger = hc.getGrapher();
 67 kkz      1.1.2.18         TreeVisitor tv = new ConstPropVisitor(hc);
 68 kkz      1.1.2.18         // we put all elements in array to avoid screwing up the
 69 kkz      1.1.2.18         // iterator as we mutate the tree in-place.
 70 kkz      1.1.2.18         Object[] elements = cfger.getElements(hc).toArray();
 71 kkz      1.1.2.18         for (int i=0; i < elements.length; i++) {
 72 kkz      1.1.2.18             ((Stm) elements[i]).accept(tv);
 73 kkz      1.1.2.18         }
 74 kkz      1.1.2.18         return hc;
 75 duncan   1.1.2.1      }
 76 duncan   1.1.2.1  
 77 kkz      1.1.2.18     private static class ConstPropVisitor extends TreeVisitor {
 78 kkz      1.1.2.18         private ReachingDefs rd;
 79 kkz      1.1.2.18         boolean changed = false;
 80 kkz      1.1.2.18 
 81 kkz      1.1.2.18         ConstPropVisitor(Code hc) {
 82 kkz      1.1.2.18             this.rd = new ReachingDefsAltImpl(hc, 
 83 kkz      1.1.2.18                                               hc.getGrapher(), 
 84 kkz      1.1.2.18                                               hc.getUseDefer());
 85 kkz      1.1.2.18         }
 86 kkz      1.1.2.18 
 87 kkz      1.1.2.18         // should never get here
 88 cananian 1.3.2.1          public void visit (Tree t) { assert false; }
 89 kkz      1.1.2.18 
 90 kkz      1.1.2.18         // ALIGNs are okay
 91 kkz      1.1.2.18         public void visit(ALIGN a) { }
 92 kkz      1.1.2.18 
 93 kkz      1.1.2.18         // for BINOPs, tricky
 94 kkz      1.1.2.18         public void visit(BINOP b) {
 95 kkz      1.1.2.18             // go up until we find a Stm so we can use a UseDefer
 96 kkz      1.1.2.18             Tree parent = parentStm(b);
 97 cananian 1.3.2.1              assert parent != null;
 98 kkz      1.1.2.18             Exp left = b.getLeft();
 99 kkz      1.1.2.18             if (left.kind() == TreeKind.TEMP) {
100 kkz      1.1.2.18                 Exp val = constant((TEMP)left, (Stm)parent, rd);
101 kkz      1.1.2.18                 if (val != null) b.setLeft(val);
102 kkz      1.1.2.18             } else {
103 kkz      1.1.2.18                 left.accept(this);
104 kkz      1.1.2.18             }
105 kkz      1.1.2.18             Exp right = b.getRight();
106 kkz      1.1.2.18             if (right.kind() == TreeKind.TEMP) {
107 kkz      1.1.2.18                 Exp val = constant((TEMP)right, (Stm)parent, rd);
108 kkz      1.1.2.18                 if (val != null) b.setRight(val);
109 kkz      1.1.2.18             } else {
110 kkz      1.1.2.18                 right.accept(this);
111 duncan   1.1.2.1              }
112 duncan   1.1.2.1          }
113 duncan   1.1.2.1  
114 kkz      1.1.2.18         // for CJUMPs, check test condition
115 kkz      1.1.2.18         public void visit(CJUMP c) {
116 kkz      1.1.2.18             Exp test = c.getTest();
117 kkz      1.1.2.18             if (test.kind() == TreeKind.TEMP) {
118 kkz      1.1.2.18                 Exp val = constant((TEMP)test, c, rd);
119 kkz      1.1.2.18                 if (val != null) c.setTest(val);
120 kkz      1.1.2.18             } else {
121 kkz      1.1.2.18                 test.accept(this);
122 kkz      1.1.2.18             }
123 duncan   1.1.2.1          }
124 duncan   1.1.2.1          
125 kkz      1.1.2.18         // CONSTs are already okay
126 kkz      1.1.2.18         public void visit(CONST c) { }
127 kkz      1.1.2.18 
128 kkz      1.1.2.18         // for DATUM, check data
129 kkz      1.1.2.18         public void visit(DATUM d) {
130 kkz      1.1.2.18             Exp data = d.getData();
131 kkz      1.1.2.18             if (data.kind() == TreeKind.TEMP) {
132 kkz      1.1.2.18                 Exp val = constant((TEMP)data, d, rd);
133 kkz      1.1.2.18                 if (val != null) d.setData(val);
134 kkz      1.1.2.18             } else {
135 kkz      1.1.2.18                 data.accept(this);
136 duncan   1.1.2.1              }
137 duncan   1.1.2.1          }
138 duncan   1.1.2.1  
139 kkz      1.1.2.18         // for EXPRs, check exp
140 kkz      1.1.2.18         public void visit(EXPR e) {
141 kkz      1.1.2.18             Exp exp = e.getExp();
142 kkz      1.1.2.18             if (exp.kind() == TreeKind.TEMP) {
143 kkz      1.1.2.18                 Exp val = constant((TEMP)exp, e, rd);
144 kkz      1.1.2.18                 if (val != null) e.setExp(val);
145 kkz      1.1.2.18             } else {
146 kkz      1.1.2.18                 exp.accept(this);
147 duncan   1.1.2.1              }
148 duncan   1.1.2.1          }
149 duncan   1.1.2.1  
150 kkz      1.1.2.18         // for INVOCATIONs, check func and args
151 kkz      1.1.2.18         public void visit (INVOCATION i) {
152 kkz      1.1.2.18             Exp func = i.getFunc();
153 kkz      1.1.2.18             if (func.kind() == TreeKind.TEMP) {
154 kkz      1.1.2.18                 Exp val = constant((TEMP)func, i, rd);
155 kkz      1.1.2.18                 if (val != null) i.setFunc(val);
156 kkz      1.1.2.18             } else {
157 kkz      1.1.2.18                 func.accept(this);
158 kkz      1.1.2.18             }
159 kkz      1.1.2.18             ExpList args = i.getArgs();
160 kkz      1.1.2.18             while(args != null) {
161 kkz      1.1.2.18                 Exp arg = args.head;
162 kkz      1.1.2.18                 if (arg.kind() == TreeKind.TEMP) {
163 kkz      1.1.2.18                     Exp val = constant((TEMP)arg, i, rd);
164 kkz      1.1.2.18                     if (val != null)
165 kkz      1.1.2.18                         i.setArgs(ExpList.replace(i.getArgs(), arg, val));
166 kkz      1.1.2.18                 } else {
167 kkz      1.1.2.18                     arg.accept(this);
168 kkz      1.1.2.18                 }
169 kkz      1.1.2.18                 args = args.tail;
170 kkz      1.1.2.18             }
171 duncan   1.1.2.1          }
172 duncan   1.1.2.1  
173 kkz      1.1.2.18         // for JUMPs, check exp
174 kkz      1.1.2.18         public void visit(JUMP j) {
175 kkz      1.1.2.18             Exp exp = j.getExp();
176 kkz      1.1.2.18             if (exp.kind() == TreeKind.TEMP) {
177 kkz      1.1.2.18                 Exp val = constant((TEMP)exp, j, rd);
178 kkz      1.1.2.18                 if (val != null) j.setExp(val);
179 kkz      1.1.2.18             } else {
180 kkz      1.1.2.18                 exp.accept(this);
181 duncan   1.1.2.1              }
182 duncan   1.1.2.1          }
183 duncan   1.1.2.1  
184 kkz      1.1.2.18         // LABELs are okay
185 kkz      1.1.2.18         public void visit(LABEL l) { }
186 kkz      1.1.2.18 
187 kkz      1.1.2.18         // for MEMs, tricky
188 kkz      1.1.2.18         public void visit(MEM m) {
189 kkz      1.1.2.18             // go up until we find a Stm so we can use a UseDefer
190 kkz      1.1.2.18             Tree parent = parentStm(m);
191 cananian 1.3.2.1              assert parent != null;
192 kkz      1.1.2.18             Exp exp = m.getExp();
193 kkz      1.1.2.18             if (exp.kind() == TreeKind.TEMP) {
194 kkz      1.1.2.18                 Exp val = constant((TEMP)exp, (Stm)parent, rd);
195 kkz      1.1.2.18                 if (val != null) m.setExp(val);
196 kkz      1.1.2.18             } else {
197 kkz      1.1.2.18                 exp.accept(this);
198 duncan   1.1.2.3              }
199 duncan   1.1.2.1          }
200 duncan   1.1.2.1  
201 kkz      1.1.2.18         // METHODs are okay
202 kkz      1.1.2.18         public void visit(METHOD m) { }
203 kkz      1.1.2.18 
204 kkz      1.1.2.18         // for MOVEs, check the src
205 kkz      1.1.2.18         public void visit(MOVE m) {
206 kkz      1.1.2.18             Exp src = m.getSrc();
207 kkz      1.1.2.18             if (src.kind() == TreeKind.TEMP) {
208 kkz      1.1.2.18                 Exp val = constant((TEMP)src, m, rd);
209 kkz      1.1.2.18                 if (val != null) m.setSrc(val);
210 kkz      1.1.2.18             } else {
211 kkz      1.1.2.18                 src.accept(this);
212 duncan   1.1.2.1              }
213 duncan   1.1.2.1          }
214 duncan   1.1.2.1  
215 kkz      1.1.2.18         // NAMEs are okay
216 kkz      1.1.2.18         public void visit(NAME n) { }
217 kkz      1.1.2.18         
218 kkz      1.1.2.18         // for RETURNs, check retval
219 kkz      1.1.2.18         public void visit(RETURN r) {
220 kkz      1.1.2.18             Exp retval = r.getRetval();
221 kkz      1.1.2.18             if (retval.kind() == TreeKind.TEMP) {
222 kkz      1.1.2.18                 Exp val = constant((TEMP)retval, r, rd);
223 kkz      1.1.2.18                 if (val != null) r.setRetval(val);
224 kkz      1.1.2.18             } else {
225 kkz      1.1.2.18                 retval.accept(this);
226 kkz      1.1.2.18             }
227 kkz      1.1.2.18         }
228 kkz      1.1.2.18 
229 kkz      1.1.2.18         // SEGMENTs are okay
230 kkz      1.1.2.18         public void visit(SEGMENT s) { }
231 kkz      1.1.2.18 
232 kkz      1.1.2.18         // TEMPs are okay
233 kkz      1.1.2.18         public void visit(TEMP t) { }
234 kkz      1.1.2.18 
235 kkz      1.1.2.18         // for THROWs, check retex and handler
236 kkz      1.1.2.18         public void visit(THROW t) {
237 kkz      1.1.2.18             Exp retex = t.getRetex();
238 kkz      1.1.2.18             if (retex.kind() == TreeKind.TEMP) {
239 kkz      1.1.2.18                 Exp val = constant((TEMP)retex, t, rd);
240 kkz      1.1.2.18                 if (val != null) t.setRetex(val);
241 kkz      1.1.2.18             } else {
242 kkz      1.1.2.18                 retex.accept(this);
243 kkz      1.1.2.18             }
244 kkz      1.1.2.18             Exp handler = t.getHandler();
245 kkz      1.1.2.18             if (handler.kind() == TreeKind.TEMP) {
246 kkz      1.1.2.18                 Exp val = constant((TEMP)handler, t, rd);
247 kkz      1.1.2.18                 if (val != null) t.setHandler(val);
248 kkz      1.1.2.18             } else {
249 kkz      1.1.2.18                 handler.accept(this);
250 kkz      1.1.2.18             }
251 kkz      1.1.2.18         }
252 kkz      1.1.2.18 
253 kkz      1.1.2.18         // for UNOPs, tricky
254 kkz      1.1.2.18         public void visit(UNOP u) {
255 kkz      1.1.2.18             // go up until we find a Stm so we can use a UseDefer
256 kkz      1.1.2.18             Tree parent = parentStm(u);
257 cananian 1.3.2.1              assert parent != null;
258 kkz      1.1.2.18             Exp operand = u.getOperand();
259 kkz      1.1.2.18             if (operand.kind() == TreeKind.TEMP) {
260 kkz      1.1.2.18                 Exp val = constant((TEMP)operand, (Stm)parent, rd);
261 kkz      1.1.2.18                 if (val != null) u.setOperand(val);
262 kkz      1.1.2.18             } else {
263 kkz      1.1.2.18                 operand.accept(this);
264 kkz      1.1.2.18             }
265 kkz      1.1.2.18         }
266 kkz      1.1.2.18 
267 kkz      1.1.2.18         // returns the parent Stm to whom this Exp belongs
268 kkz      1.1.2.18         private static Stm parentStm(Exp exp) {
269 kkz      1.1.2.18             Tree parent = exp.getParent();
270 kkz      1.1.2.18             while (!(parent instanceof Stm))
271 kkz      1.1.2.18                 parent = parent.getParent();
272 kkz      1.1.2.18             return (Stm)parent;
273 kkz      1.1.2.18         }
274 kkz      1.1.2.18 
275 kkz      1.1.2.18         // returns a CONST or NAME if the given TEMP can be
276 kkz      1.1.2.18         // replaced by such. else returns null.
277 kkz      1.1.2.18         private static Exp constant(TEMP T, Stm parent, ReachingDefs rd) {
278 kkz      1.1.2.18             Set s = rd.reachingDefs(parent, T.temp);
279 kkz      1.1.2.18             // if no definitions reach, then this
280 kkz      1.1.2.18             // is dead code, and we're done
281 kkz      1.1.2.18             if (s.size() == 0)
282 kkz      1.1.2.18                 return null;
283 kkz      1.1.2.18             // all the definitions must be MOVEs with
284 kkz      1.1.2.18             // equivalent CONSTs or NAMEs as sources
285 kkz      1.1.2.18             Iterator it = s.iterator();
286 kkz      1.1.2.18             // all definitions are Stms
287 kkz      1.1.2.18             Stm first = (Stm) it.next();
288 kkz      1.1.2.18             if (first.kind() != TreeKind.MOVE) return null;
289 kkz      1.1.2.18             Exp firstSrc = ((MOVE) first).getSrc();
290 kkz      1.1.2.18             // if the first MOVE we see fits
291 kkz      1.1.2.18             // our criterion, continue
292 kkz      1.1.2.18             // all subsequent MOVEs must have
293 kkz      1.1.2.18             // equivalent sources
294 kkz      1.1.2.18             if (firstSrc.kind() == TreeKind.CONST) {
295 kkz      1.1.2.18                 CONST c = (CONST) firstSrc;
296 kkz      1.1.2.18                 while(it.hasNext()) {
297 kkz      1.1.2.18                     // check for match
298 kkz      1.1.2.18                     Stm stm = (Stm) it.next();
299 kkz      1.1.2.18                     Number n = c.value();
300 kkz      1.1.2.18                     if (stm.kind() != TreeKind.MOVE) return null;
301 kkz      1.1.2.18                     Exp src = ((MOVE) stm).getSrc();
302 kkz      1.1.2.18                     if (src.kind() != TreeKind.CONST ||
303 kkz      1.1.2.18                         src.type() != c.type())
304 kkz      1.1.2.18                         return null;
305 kkz      1.1.2.18                     if (n == null) {
306 kkz      1.1.2.18                         if (((CONST) src).value() != null) return null;
307 kkz      1.1.2.18                     } else {
308 kkz      1.1.2.18                         if (!((CONST) src).value().equals(n)) return null;
309 duncan   1.1.2.1                      }
310 duncan   1.1.2.1                  }
311 kkz      1.1.2.18                 // done!
312 kkz      1.1.2.18                 return (Exp)c.clone();
313 kkz      1.1.2.18             } else if (firstSrc.kind() == TreeKind.NAME) {
314 kkz      1.1.2.18                 NAME n = (NAME) firstSrc;
315 kkz      1.1.2.18                 while(it.hasNext()) {
316 kkz      1.1.2.18                     // check for match
317 kkz      1.1.2.18                     Stm stm = (Stm) it.next();
318 kkz      1.1.2.18                     if (stm.kind() != TreeKind.MOVE) return null;
319 kkz      1.1.2.18                     Exp src = ((MOVE) stm).getSrc();
320 kkz      1.1.2.18                     if (src.kind() != TreeKind.NAME ||
321 kkz      1.1.2.18                         !((NAME) src).label.equals(n.label))
322 kkz      1.1.2.18                         return null;
323 kkz      1.1.2.18                     // all NAMEs have type Type.POINTER
324 cananian 1.3.2.1                      assert src.type() == n.type();
325 kkz      1.1.2.18                 }
326 kkz      1.1.2.18                 // done!
327 kkz      1.1.2.18                 return (Exp)n.clone();
328 duncan   1.1.2.1              }
329 kkz      1.1.2.18             return null;
330 duncan   1.1.2.6          }
331 duncan   1.1.2.1      }
332 cananian 1.2      }