1 cananian 1.1.2.4 // Peephole.java, created Sun Dec 27 19:37:24 1998 by cananian 2 cananian 1.1.2.7 // Copyright (C) 1998 C. Scott Ananian <cananian@alumni.princeton.edu> 3 cananian 1.1.2.7 // Licensed under the terms of the GNU GPL; see COPYING for details. 4 cananian 1.1.2.1 package harpoon.IR.Quads; 5 cananian 1.1.2.1 6 cananian 1.1.2.1 import harpoon.Temp.Temp; 7 cananian 1.1.2.4 import harpoon.Temp.TempMap; 8 bdemsky 1.1.2.11 import harpoon.Util.Tuple; 9 cananian 1.5 import net.cscott.jutil.UniqueStack; 10 cananian 1.1.2.4 import harpoon.Util.Util; 11 cananian 1.1.2.4 12 cananian 1.1.2.14 import java.util.HashSet; 13 bdemsky 1.1.2.11 import java.util.Map; 14 cananian 1.1.2.14 import java.util.Set; 15 cananian 1.1.2.1 /** 16 cananian 1.1.2.4 * <code>Peephole</code> performs peephole optimizations (mostly 17 cananian 1.1.2.4 * <code>MOVE</code> collation) on <code>QuadWithTry</code> and 18 cananian 1.1.2.4 * <code>QuadNoSSA</code> forms. 19 cananian 1.1.2.1 * 20 cananian 1.1.2.1 * @author C. Scott Ananian <cananian@alumni.princeton.edu> 21 cananian 1.5 * @version $Id: Peephole.java,v 1.5 2004/02/08 01:55:25 cananian Exp $ 22 cananian 1.1.2.1 */ 23 cananian 1.1.2.1 24 cananian 1.1.2.4 final class Peephole { 25 cananian 1.1.2.4 final static void normalize(Quad head) { 26 cananian 1.1.2.19 SwapVisitor sv = new SwapVisitor(null, head); 27 cananian 1.1.2.4 sv.optimize(head); // usually things are screwy after trans. 28 cananian 1.1.2.1 } 29 bdemsky 1.1.2.11 30 bdemsky 1.1.2.11 final static void normalize(Quad head, Map typemap) { 31 cananian 1.1.2.19 SwapVisitor sv = new SwapVisitor(typemap, head); 32 bdemsky 1.1.2.11 sv.optimize(head); // usually things are screwy after trans. 33 bdemsky 1.1.2.11 } 34 bdemsky 1.1.2.11 35 cananian 1.1.2.20 final static void optimize(Quad head) { 36 cananian 1.1.2.20 optimize(head, null); 37 bdemsky 1.1.2.11 } 38 bdemsky 1.1.2.11 39 cananian 1.1.2.20 final static void optimize(Quad head, Map typemap) { 40 cananian 1.1.2.19 PeepholeVisitor pv = new PeepholeVisitor(typemap, head); 41 cananian 1.1.2.4 while (pv.optimize(head)) 42 cananian 1.1.2.4 /*repeat*/; 43 cananian 1.1.2.4 } 44 bdemsky 1.1.2.11 45 cananian 1.1.2.19 private static class CheckStack extends UniqueStack { 46 cananian 1.1.2.19 public void push(Object o) { 47 cananian 1.3.2.1 assert o!=null; 48 cananian 1.1.2.4 Quad[] ql = ((Quad)o).next(); 49 cananian 1.1.2.4 for (int i=0; i<ql.length; i++) 50 cananian 1.3.2.1 assert ql[i]!=null; 51 cananian 1.1.2.19 super.push(o); 52 cananian 1.1.2.1 } 53 cananian 1.1.2.4 } 54 cananian 1.1.2.4 private abstract static class SuperVisitor extends QuadVisitor { 55 cananian 1.1.2.19 final METHOD method; 56 cananian 1.1.2.19 SuperVisitor(Quad head) { this.method = (METHOD) head.next(1); } 57 cananian 1.1.2.19 58 cananian 1.1.2.19 final UniqueStack todo = new CheckStack(); 59 pnkfelix 1.1.2.6 final Set visited = new HashSet(); 60 cananian 1.1.2.4 boolean changed = false; 61 cananian 1.1.2.4 62 cananian 1.1.2.4 public boolean optimize(Quad head) { 63 cananian 1.1.2.4 changed = false; 64 cananian 1.1.2.19 todo.clear(); 65 cananian 1.1.2.4 visited.clear(); 66 cananian 1.1.2.4 67 cananian 1.1.2.4 todo.push(head); 68 cananian 1.1.2.4 while (!todo.empty()) { 69 cananian 1.1.2.4 Quad q = (Quad) todo.pop(); 70 cananian 1.1.2.4 if (!visited.contains(q)) { 71 cananian 1.1.2.9 q.accept(this); 72 cananian 1.1.2.4 } 73 cananian 1.1.2.4 } 74 cananian 1.1.2.4 return changed; 75 cananian 1.1.2.4 } 76 cananian 1.1.2.19 protected boolean sameHandlers(Quad q1, Quad q2) { 77 cananian 1.1.2.19 for (int i=1; i<method.nextLength(); i++) { 78 cananian 1.1.2.19 HANDLER handler = (HANDLER) method.next(i); 79 cananian 1.1.2.19 if (handler.isProtected(q1) != handler.isProtected(q2)) 80 cananian 1.1.2.19 return false; 81 cananian 1.1.2.19 } 82 cananian 1.1.2.19 return true; 83 cananian 1.1.2.19 } 84 cananian 1.1.2.4 } 85 cananian 1.1.2.4 private final static class SwapVisitor extends SuperVisitor { 86 bdemsky 1.1.2.11 private Map typemap; 87 bdemsky 1.1.2.11 88 cananian 1.1.2.19 public SwapVisitor(Map typemap, Quad head) { 89 cananian 1.1.2.19 super(head); 90 bdemsky 1.1.2.11 this.typemap=typemap; 91 bdemsky 1.1.2.11 } 92 bdemsky 1.1.2.11 93 cananian 1.1.2.4 public void visit(Quad q) { 94 cananian 1.1.2.4 Quad[] ql=q.next(); 95 cananian 1.1.2.19 // very specific case for swaparoo: 96 cananian 1.1.2.19 // tA = oper .. -\ tB = oper .. 97 cananian 1.1.2.19 // tB = MOVE tA -/ tA = MOVE tB 98 cananian 1.1.2.19 // ONLY VALID IF BOTH ARE IN SAME HANDLER CONTEXT! 99 cananian 1.1.2.4 if (ql.length==1 && ql[0] instanceof MOVE && 100 bdemsky 1.1.2.17 !(q instanceof METHOD) && q.def().length==1 && 101 cananian 1.1.2.19 q.def()[0]==((MOVE)ql[0]).src() && 102 cananian 1.1.2.19 sameHandlers(q, ql[0])) { 103 cananian 1.1.2.4 MOVE Qm = (MOVE)ql[0]; 104 cananian 1.1.2.4 TempMap tm0 = new OneToOneMap(Qm.src(), Qm.dst()); 105 cananian 1.1.2.4 TempMap tm1 = new OneToOneMap(Qm.dst(), Qm.src()); 106 cananian 1.1.2.4 Quad q1 = q.rename(q.qf, tm0, null); 107 cananian 1.1.2.4 Quad q2 = Qm.rename(Qm.qf, tm1, tm0); 108 bdemsky 1.1.2.11 if (typemap!=null) { 109 bdemsky 1.1.2.11 typemap.put(new Tuple(new Object[]{q1,Qm.dst() }), 110 bdemsky 1.1.2.11 typemap.get(new Tuple(new Object[]{Qm, Qm.dst()}))); 111 bdemsky 1.1.2.11 Temp uses[]=q.use(); 112 bdemsky 1.1.2.11 for (int i=0;i<uses.length;i++) 113 bdemsky 1.1.2.11 typemap.put(new Tuple(new Object[]{q1, uses[i]}), 114 bdemsky 1.1.2.11 typemap.get(new Tuple(new Object[] {q, uses[i]}))); 115 bdemsky 1.1.2.11 typemap.put(new Tuple(new Object[]{q2, Qm.src()}), 116 bdemsky 1.1.2.11 typemap.get(new Tuple(new Object[] {Qm, Qm.src()}))); 117 bdemsky 1.1.2.11 typemap.put(new Tuple(new Object[]{q2, Qm.dst()}), 118 bdemsky 1.1.2.11 typemap.get(new Tuple(new Object[] {Qm, Qm.dst()}))); 119 bdemsky 1.1.2.11 120 bdemsky 1.1.2.11 } 121 cananian 1.1.2.12 replace(q, q1); 122 cananian 1.1.2.12 replace(Qm, q2); 123 cananian 1.1.2.14 visited.add(q1); visited.add(q2); 124 cananian 1.1.2.4 todo.push(q2.next(0)); 125 cananian 1.1.2.4 changed=true; 126 cananian 1.1.2.4 } else { 127 cananian 1.1.2.4 // garden variety instruction. 128 cananian 1.1.2.4 for (int i=0; i<ql.length; i++) 129 cananian 1.1.2.4 todo.push(ql[i]); 130 cananian 1.1.2.14 visited.add(q); 131 cananian 1.1.2.4 } 132 cananian 1.1.2.4 } 133 cananian 1.1.2.4 } 134 cananian 1.1.2.4 private final static class PeepholeVisitor extends SuperVisitor { 135 bdemsky 1.1.2.11 private Map typemap; 136 bdemsky 1.1.2.11 137 cananian 1.1.2.19 PeepholeVisitor(Map typemap, Quad head) { 138 cananian 1.1.2.19 super(head); 139 bdemsky 1.1.2.11 this.typemap=typemap; 140 bdemsky 1.1.2.11 } 141 bdemsky 1.1.2.11 142 cananian 1.1.2.4 public void visit(Quad q) { 143 cananian 1.1.2.4 Quad[] ql=q.next(); 144 cananian 1.1.2.4 for (int i=0; i<ql.length; i++) 145 cananian 1.1.2.4 todo.push(ql[i]); 146 cananian 1.1.2.14 visited.add(q); 147 cananian 1.1.2.4 } 148 bdemsky 1.1.2.11 149 bdemsky 1.1.2.11 void fixmap(Quad old, Quad newq, TempMap tm) { 150 bdemsky 1.1.2.11 if (typemap!=null) { 151 bdemsky 1.1.2.11 Temp[] defs=old.def(); 152 bdemsky 1.1.2.11 for (int i=0;i<defs.length;i++) { 153 bdemsky 1.1.2.11 typemap.put(new Tuple(new Object[]{newq, defs[i]}), 154 bdemsky 1.1.2.11 typemap.get(new Tuple(new Object[]{old, defs[i]}))); 155 bdemsky 1.1.2.11 } 156 bdemsky 1.1.2.11 Temp[] uses=old.use(); 157 bdemsky 1.1.2.11 for (int i=0;i<uses.length;i++) { 158 bdemsky 1.1.2.13 if (tm==null) 159 bdemsky 1.1.2.11 typemap.put(new Tuple(new Object[]{newq, uses[i]}), 160 bdemsky 1.1.2.11 typemap.get(new Tuple(new Object[]{old, uses[i]}))); 161 bdemsky 1.1.2.11 else 162 bdemsky 1.1.2.11 typemap.put(new Tuple(new Object[]{newq, tm.tempMap(uses[i])}), 163 bdemsky 1.1.2.11 typemap.get(new Tuple(new Object[]{old, uses[i]}))); 164 bdemsky 1.1.2.11 } 165 bdemsky 1.1.2.11 } 166 bdemsky 1.1.2.11 } 167 bdemsky 1.1.2.11 168 cananian 1.1.2.4 public void visit(final MOVE q) { 169 cananian 1.1.2.4 final Quad Qnext = q.next(0); 170 cananian 1.1.2.4 if (q.dst() == q.src()) { 171 cananian 1.1.2.4 // dst==src, delete. 172 cananian 1.1.2.4 todo.push(unlink(q)); 173 cananian 1.1.2.4 changed=true; 174 cananian 1.1.2.4 } else if (isMember(q.dst(), Qnext.def())) { 175 cananian 1.1.2.4 // rename Qnext & delete MOVE. 176 cananian 1.1.2.4 TempMap tm = new OneToOneMap(q.dst(), q.src()); 177 bdemsky 1.1.2.11 Quad newquad=Qnext.rename(Qnext.qf, null, tm); 178 bdemsky 1.1.2.11 fixmap(Qnext, newquad, tm); 179 cananian 1.1.2.12 replace(Qnext, newquad); 180 cananian 1.1.2.4 // unlink MOVE 181 cananian 1.1.2.4 todo.push(unlink(q)); 182 cananian 1.1.2.4 changed=true; 183 cananian 1.1.2.4 } else { 184 cananian 1.1.2.4 // see if we can move the MOVE forward. 185 cananian 1.1.2.4 // (we can move it ahead until someone redefines our src/def) 186 cananian 1.1.2.4 Quad Qp; boolean pastNonMove=false; 187 cananian 1.1.2.4 boolean moveit=false, deleteit=false; 188 cananian 1.1.2.10 for (Qp=Qnext; true; Qp=Qp.next(0)) { 189 cananian 1.1.2.4 if (Qp instanceof FOOTER) { 190 cananian 1.1.2.4 // move isn't useful after return! 191 cananian 1.1.2.4 deleteit=true; 192 cananian 1.1.2.4 break; 193 cananian 1.1.2.4 } 194 cananian 1.1.2.19 // we stop as soon as we come to: 195 cananian 1.1.2.19 // - a quad belonging to a different handler set 196 cananian 1.1.2.19 // - a PHI or SIGMA (only optimize within basic blocks) 197 cananian 1.1.2.19 // - a statement which destroys the source temp 198 cananian 1.1.2.19 if (!sameHandlers(q, Qp) || 199 cananian 1.1.2.19 Qp instanceof PHI || Qp instanceof SIGMA || 200 cananian 1.1.2.19 isMember(q.src(), Qp.def())) { 201 cananian 1.1.2.4 if (pastNonMove) moveit=true; 202 cananian 1.1.2.19 // enable more moves 203 cananian 1.1.2.19 //if (Qp instanceof SIGMA) moveit=true; 204 cananian 1.1.2.4 break; 205 cananian 1.1.2.4 } 206 cananian 1.1.2.19 207 cananian 1.1.2.4 if (isMember(q.dst(), Qp.def())) { 208 cananian 1.1.2.4 // destroys def, so move isn't useful anymore. 209 cananian 1.1.2.4 if (pastNonMove) moveit=true; 210 cananian 1.1.2.4 // BE CAREFUL: Qp may *use* q.dst(), so 'deleteit' is 211 cananian 1.1.2.4 // not correct. 212 cananian 1.1.2.4 break; 213 cananian 1.1.2.4 } 214 cananian 1.1.2.4 if (!(Qp instanceof MOVE)) pastNonMove=true; 215 cananian 1.1.2.4 } 216 cananian 1.1.2.10 // we're going to unlink and move this quad if: 217 cananian 1.1.2.10 // -- moveit is true, or 218 cananian 1.1.2.10 // -- deleteit is true, or 219 cananian 1.1.2.10 // -- Qp is a 'safe' sigma function where safe means: 220 cananian 1.1.2.19 // - belongs to same handlers as q 221 cananian 1.1.2.10 // note that we'll move quads even if Qp is unsafe, if 222 cananian 1.1.2.10 // moveit is true. deleteit can't be true if Qp is a 223 cananian 1.1.2.10 // SIGMA. 224 cananian 1.1.2.19 if (moveit || deleteit) { 225 cananian 1.1.2.4 TempMap tm = new OneToOneMap(q.dst(), q.src()); 226 cananian 1.1.2.4 Edge lstE; 227 cananian 1.1.2.4 for (lstE=q.nextEdge(0); lstE.to() != Qp; ) { 228 cananian 1.1.2.4 Quad qq = (Quad)lstE.to(); 229 bdemsky 1.1.2.11 Quad newquad=qq.rename(qq.qf, null, tm); 230 bdemsky 1.1.2.11 fixmap(qq,newquad,tm); 231 cananian 1.1.2.12 replace(qq, newquad); 232 cananian 1.1.2.4 lstE=((Quad)lstE.from()).next(0).nextEdge(0); 233 cananian 1.1.2.4 } 234 cananian 1.1.2.15 HandlerSet hs=q.handlers(); 235 cananian 1.1.2.4 todo.push(unlink(q)); 236 cananian 1.1.2.10 // usually we relink the MOVE quad before Qp, but 237 cananian 1.1.2.10 // we'll relink *after* a sigma if we can -- this 238 cananian 1.1.2.10 // helps keep the MOVEs propagating. Relink *after* 239 cananian 1.1.2.10 // if sigma doesn't redefine the source of the MOVE 240 cananian 1.1.2.19 // and if sigma belongs to the same handler region. 241 cananian 1.1.2.19 if (Qp instanceof SIGMA && sameHandlers(q, Qp) && 242 cananian 1.1.2.10 !(Qp instanceof CALL && 243 cananian 1.1.2.10 (q.src()==((CALL)Qp).retval() || 244 cananian 1.1.2.10 q.src()==((CALL)Qp).retex()))) { 245 cananian 1.1.2.4 SIGMA Qs = (SIGMA) Qp.rename(Qp.qf, null, tm); 246 bdemsky 1.1.2.11 fixmap(Qp, Qs, tm); 247 cananian 1.1.2.4 todo.removeElement(Qp); // remove old SIGMA from todo 248 cananian 1.1.2.12 replace(Qp, Qs); 249 cananian 1.1.2.10 // we can just delete the MOVE if the CALL 250 cananian 1.1.2.10 // overwrites the destination. 251 cananian 1.1.2.10 if (Qp instanceof CALL && 252 cananian 1.1.2.10 (q.dst() == ((CALL)Qp).retval() || 253 cananian 1.1.2.10 q.dst() == ((CALL)Qp).retex())) { 254 cananian 1.1.2.10 // the move is gone & we don't need it any mo' 255 cananian 1.1.2.10 changed=true; 256 cananian 1.1.2.10 return; 257 cananian 1.1.2.10 } 258 cananian 1.1.2.4 Edge[] el = Qs.nextEdge(); 259 cananian 1.1.2.4 for (int i=0; i<el.length; i++) { 260 cananian 1.1.2.4 MOVE Qm = (i==0) ? q : (MOVE)q.clone(); 261 bdemsky 1.1.2.13 if (i!=0) 262 bdemsky 1.1.2.13 fixmap(q, Qm, null); 263 cananian 1.1.2.4 Quad.addEdge((Quad)el[i].from(),el[i].which_succ(), 264 cananian 1.1.2.4 Qm, 0); 265 cananian 1.1.2.4 Quad.addEdge(Qm, 0, 266 cananian 1.1.2.4 (Quad)el[i].to(), el[i].which_pred()); 267 cananian 1.1.2.4 // those nasty HANDLERs 268 cananian 1.1.2.15 Qm.addHandlers(hs); 269 cananian 1.1.2.4 } 270 cananian 1.1.2.4 } else if (moveit) { // relink before Qend 271 cananian 1.1.2.4 Quad.addEdge((Quad)lstE.from(),lstE.which_succ(), q,0); 272 cananian 1.1.2.4 Quad.addEdge(q,0, (Quad)lstE.to(), lstE.which_pred()); 273 cananian 1.1.2.15 q.addHandlers(hs); 274 cananian 1.3.2.1 } else assert deleteit; 275 cananian 1.1.2.4 changed=true; 276 cananian 1.1.2.4 } else { 277 cananian 1.1.2.4 // do nothing. 278 cananian 1.1.2.14 visited.add(q); 279 cananian 1.1.2.4 todo.push(Qnext); 280 cananian 1.1.2.4 } 281 cananian 1.1.2.4 } 282 cananian 1.1.2.4 } 283 cananian 1.1.2.4 private static Quad unlink(Quad q) { 284 cananian 1.1.2.4 Edge in = q.prevEdge(0), out = q.nextEdge(0); 285 cananian 1.1.2.4 Quad.addEdge((Quad)in.from(), in.which_succ(), 286 cananian 1.1.2.4 (Quad)out.to(), out.which_pred()); 287 cananian 1.1.2.15 q.removeHandlers(q.handlers()); 288 cananian 1.1.2.4 return (Quad)out.to(); 289 cananian 1.1.2.4 } 290 cananian 1.1.2.4 private static boolean isMember(Temp t, Temp[] Tset) { 291 cananian 1.1.2.4 for (int i=0; i<Tset.length; i++) 292 cananian 1.1.2.4 if (t == Tset[i]) return true; 293 cananian 1.1.2.4 return false; 294 cananian 1.1.2.4 } 295 cananian 1.1.2.4 } 296 cananian 1.1.2.12 // replace oldQ with newQ, updating handlers, too. 297 cananian 1.1.2.12 private static void replace(Quad oldQ, Quad newQ) { 298 cananian 1.1.2.12 Quad.replace(oldQ, newQ); 299 cananian 1.1.2.12 Quad.transferHandlers(oldQ, newQ); 300 cananian 1.1.2.12 } 301 cananian 1.1.2.12 // simple temp mapping. 302 cananian 1.1.2.4 private static class OneToOneMap implements TempMap { 303 cananian 1.1.2.4 final Temp from; 304 cananian 1.1.2.4 final Temp to; 305 cananian 1.1.2.4 OneToOneMap(Temp from, Temp to) { this.from=from; this.to=to; } 306 cananian 1.1.2.4 public Temp tempMap(Temp t) { return (t==from) ? to : t; } 307 cananian 1.1.2.1 } 308 cananian 1.2 }