1 cananian 1.1.2.1 // Print.java, created Thu Dec 17 17:31:26 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.6 import harpoon.ClassFile.HCodeElement; 7 cananian 1.1.2.13 import harpoon.ClassFile.HCode.PrintCallback; 8 cananian 1.1.2.8 import harpoon.IR.LowQuad.PCALL; 9 cananian 1.1.2.8 import harpoon.Temp.Temp; 10 cananian 1.1.2.2 import harpoon.Util.Util; 11 cananian 1.1.2.1 12 cananian 1.1.2.1 import java.io.PrintWriter; 13 cananian 1.1.2.4 import java.util.Enumeration; 14 cananian 1.1.2.9 import java.util.HashMap; 15 cananian 1.1.2.9 import java.util.Map; 16 cananian 1.1.2.1 17 cananian 1.1.2.1 /** 18 cananian 1.1.2.1 * The <code>Print</code> class pretty-prints a quad representation, 19 cananian 1.1.2.1 * inserting labels to make the control flow clear. 20 cananian 1.1.2.1 * 21 cananian 1.1.2.1 * @author C. Scott Ananian <cananian@alumni.princeton.edu> 22 cananian 1.5 * @version $Id: Print.java,v 1.5 2003/07/10 02:18:23 cananian Exp $ 23 cananian 1.1.2.1 */ 24 cananian 1.1.2.1 abstract class Print { 25 cananian 1.1.2.1 /** Print <code>Quad</code> code representation <code>c</code> to 26 cananian 1.1.2.13 * <code>PrintWriter</code> <code>pw</code> using the specified 27 cananian 1.1.2.13 * <code>PrintCallback</code>. */ 28 cananian 1.3.2.2 final static void print(PrintWriter pw, Code c, PrintCallback<Quad> callback) { 29 cananian 1.3.2.2 if (callback==null) callback = new PrintCallback<Quad>(); // nop callback 30 cananian 1.1.2.1 // get elements. 31 cananian 1.3.2.2 Quad[] ql = c.getElements(); 32 cananian 1.1.2.4 METHOD qM = ((HEADER) c.getRootElement()).method(); 33 cananian 1.1.2.1 // compile list of back edges 34 cananian 1.3.2.2 Map<Quad,Label> labels = new HashMap<Quad,Label>(); 35 cananian 1.1.2.1 for (int i=0; i<ql.length; i++) { 36 cananian 1.1.2.1 // if has more than one edge, then other edges branch to labels. 37 cananian 1.1.2.1 for (int j=0; j<ql[i].next().length; j++) { 38 cananian 1.1.2.1 if (j!=0 || i==ql.length-1 || ql[i].next(j)!=ql[i+1] || 39 cananian 1.1.2.10 ql[i] instanceof SWITCH || ql[i] instanceof TYPESWITCH) 40 cananian 1.1.2.1 if (!labels.containsKey(ql[i].next(j))) 41 cananian 1.1.2.1 labels.put(ql[i].next(j), new Label()); 42 cananian 1.1.2.1 if (ql[i].next(j) instanceof PHI) 43 cananian 1.1.2.1 if (!labels.containsKey(ql[i])) 44 cananian 1.1.2.1 labels.put(ql[i], new Label()); 45 cananian 1.1.2.1 } 46 cananian 1.1.2.1 } 47 cananian 1.1.2.1 // number labels. 48 cananian 1.1.2.1 for (int i=0, j=0; i<ql.length; i++) 49 cananian 1.1.2.1 if (labels.containsKey(ql[i])) 50 cananian 1.3.2.2 labels.get(ql[i]).renumber(j++); 51 cananian 1.1.2.1 52 cananian 1.1.2.1 // okay, print these pookies. 53 cananian 1.1.2.1 pw.println("Codeview \""+c.getName()+"\" for "+c.getMethod()+":"); 54 cananian 1.1.2.4 HandlerSet hs = null; // no handlers at top. 55 cananian 1.1.2.1 for (int i=0; i<ql.length; i++) { 56 cananian 1.1.2.11 // make label and description string. 57 cananian 1.1.2.1 String l = (labels.containsKey(ql[i])) ? 58 cananian 1.1.2.1 labels.get(ql[i]).toString()+":" : ""; 59 cananian 1.1.2.1 String s = ql[i].toString(); 60 cananian 1.1.2.4 61 cananian 1.1.2.4 // determine if HandlerSet has changed & print if necessary. 62 cananian 1.1.2.4 HandlerSet oldHS = hs; hs = handlers(qM, ql[i]); 63 cananian 1.1.2.4 if (!HandlerSet.equals(oldHS, hs)) { // changed, print update. 64 cananian 1.1.2.4 StringBuffer sb=new StringBuffer("-- new handlers ["); 65 cananian 1.1.2.5 for (HandlerSet hsp=hs; hsp!=null; hsp=hsp.next) { 66 cananian 1.1.2.5 sb.append(labels.get(hsp.h)); 67 cananian 1.1.2.5 if (hsp.next!=null) sb.append(", "); 68 cananian 1.1.2.4 } 69 cananian 1.1.2.4 sb.append("] --"); 70 cananian 1.1.2.4 indent(pw, null, sb.toString()); 71 cananian 1.1.2.4 } 72 cananian 1.1.2.13 // printBefore callback. 73 cananian 1.1.2.13 callback.printBefore(pw, ql[i]); 74 cananian 1.1.2.1 // Add footer tag to HEADER quads. 75 cananian 1.1.2.1 if (ql[i] instanceof HEADER) 76 cananian 1.1.2.1 s += " [footer at "+labels.get(ql[i].next(0))+"]"; 77 cananian 1.1.2.10 // Print CALL, CJMP, SWITCH, TYPESWITCH & PHI specially. 78 cananian 1.1.2.1 if (ql[i] instanceof CJMP) { 79 cananian 1.1.2.1 CJMP Q = (CJMP) ql[i]; 80 cananian 1.1.2.1 indent(pw, ql[i], l, 81 cananian 1.1.2.1 "CJMP " + Q.test() + ", " + labels.get(Q.next(1))); 82 cananian 1.1.2.1 indent(pw, Q); 83 cananian 1.1.2.1 } else if (ql[i] instanceof SWITCH) { 84 cananian 1.1.2.1 SWITCH Q = (SWITCH) ql[i]; 85 cananian 1.1.2.1 indent(pw, ql[i], l, "SWITCH "+Q.index()); 86 cananian 1.1.2.10 for (int j=0; j<Q.keysLength(); j++) 87 cananian 1.1.2.10 indent(pw, null, " "+ 88 cananian 1.1.2.10 "case "+Q.keys(j)+": " + 89 cananian 1.1.2.10 "goto "+labels.get(Q.next(j))); 90 cananian 1.1.2.10 indent(pw, null, " "+ 91 cananian 1.1.2.10 "default: goto "+labels.get(Q.next(Q.keysLength()))); 92 cananian 1.1.2.10 indent(pw, Q); 93 cananian 1.1.2.10 } else if (ql[i] instanceof TYPESWITCH) { 94 cananian 1.1.2.10 TYPESWITCH Q = (TYPESWITCH) ql[i]; 95 cananian 1.1.2.10 indent(pw, ql[i], l, "TYPESWITCH "+Q.index()); 96 cananian 1.1.2.1 for (int j=0; j<Q.keysLength(); j++) 97 cananian 1.1.2.1 indent(pw, null, " "+ 98 cananian 1.1.2.1 "case "+Q.keys(j)+": " + 99 cananian 1.1.2.1 "goto "+labels.get(Q.next(j))); 100 cananian 1.1.2.12 if (Q.hasDefault()) 101 cananian 1.1.2.12 indent(pw, null, " "+ 102 cananian 1.1.2.12 "default: goto "+labels.get(Q.next(Q.keysLength()))); 103 cananian 1.1.2.1 indent(pw, Q); 104 cananian 1.1.2.1 } else if (ql[i] instanceof PHI) { 105 cananian 1.1.2.1 PHI Q = (PHI) ql[i]; 106 cananian 1.1.2.1 if (Q instanceof LABEL) { // ADD a label tag. 107 cananian 1.1.2.1 indent(pw, null, l, "LABEL "+((LABEL)Q).label()); 108 cananian 1.1.2.1 l=""; 109 cananian 1.1.2.1 } 110 cananian 1.1.2.1 StringBuffer sb=new StringBuffer("PHI["); 111 cananian 1.1.2.1 for (int j=0; j<Q.arity(); j++) { 112 cananian 1.1.2.1 sb.append(labels.get(Q.prev(j))); 113 cananian 1.1.2.1 if (j<Q.arity()-1) sb.append(", "); 114 cananian 1.1.2.1 } 115 cananian 1.1.2.1 sb.append("]"); 116 cananian 1.1.2.1 indent(pw, ql[i], l, sb.toString()); 117 cananian 1.1.2.1 indent(pw, Q); 118 cananian 1.1.2.8 } else if (ql[i] instanceof CALL || ql[i] instanceof PCALL) { 119 cananian 1.1.2.8 SIGMA Q = (SIGMA) ql[i]; 120 cananian 1.1.2.8 // reformat stuff after 'exceptions' 121 cananian 1.1.2.8 int j = s.indexOf(" exceptions "); 122 cananian 1.3.2.1 assert j>=0 : "(P)CALL.toString() changed, oops."; 123 cananian 1.1.2.8 indent(pw, Q, l, s.substring(0, j)); 124 cananian 1.1.2.8 Temp retex = (Q instanceof CALL) 125 cananian 1.1.2.8 ? ((CALL)Q).retex() : ((PCALL)Q).retex(); 126 cananian 1.1.2.8 if (retex!=null) // suppress exc info if not applicable 127 cananian 1.1.2.8 indent(pw, null, null, " exception in "+retex+"; "+ 128 cananian 1.1.2.8 "handler at "+labels.get(Q.next(1))); 129 cananian 1.1.2.8 indent(pw, Q); // print sigma functions. 130 cananian 1.1.2.3 } else if (ql[i] instanceof METHOD) { 131 cananian 1.1.2.3 indent(pw, ql[i], l, s); 132 cananian 1.1.2.3 StringBuffer sb = new StringBuffer(); 133 cananian 1.1.2.3 int n = ql[i].next().length; 134 cananian 1.1.2.3 for (int j=1; j < n; j++) { 135 cananian 1.1.2.3 sb.append(labels.get(ql[i].next(j))); 136 cananian 1.1.2.3 if (j < n-1) sb.append(", "); 137 cananian 1.1.2.3 } 138 cananian 1.1.2.3 if (n>1) 139 cananian 1.1.2.3 indent(pw, null, null, " handlers at ["+sb+"]"); 140 cananian 1.1.2.1 } else indent(pw, ql[i], l, s); 141 cananian 1.1.2.1 142 cananian 1.1.2.1 // DEFAULT branch for HEADER is 1-edge. For all others, 0-edge. 143 cananian 1.1.2.1 int j = (ql[i] instanceof HEADER)?1:0; 144 cananian 1.1.2.1 if (i<ql.length-1 && ql[i].next(j) != ql[i+1]) { 145 cananian 1.5 if (ql[i].next(j) instanceof FOOTER) 146 cananian 1.1.2.1 indent(pw, null, 147 cananian 1.5 "[footer at "+labels.get(ql[i].next(j))+"]"); 148 cananian 1.1.2.1 else 149 cananian 1.5 indent(pw, null, "goto "+labels.get(ql[i].next(j))); 150 cananian 1.1.2.1 } 151 cananian 1.1.2.13 // printAfter callback. 152 cananian 1.1.2.13 callback.printAfter(pw, ql[i]); 153 cananian 1.1.2.1 } 154 cananian 1.1.2.1 pw.println(); 155 cananian 1.1.2.11 pw.flush(); 156 cananian 1.1.2.1 } 157 cananian 1.1.2.1 /** Pretty-print a PHI. */ 158 cananian 1.1.2.1 static void indent(PrintWriter pw, PHI p) { 159 cananian 1.1.2.1 for (int i=0; i<p.numPhis(); i++) { 160 cananian 1.1.2.1 StringBuffer sb = new StringBuffer(); 161 cananian 1.1.2.1 sb.append(p.dst(i)); 162 cananian 1.1.2.1 sb.append("=phi("); 163 cananian 1.1.2.1 for (int j=0; j<p.arity(); j++) { 164 cananian 1.1.2.1 sb.append(p.src(i, j)); 165 cananian 1.1.2.1 if (j<p.arity()-1) sb.append(", "); 166 cananian 1.1.2.1 } 167 cananian 1.1.2.1 sb.append(")"); 168 cananian 1.1.2.1 indent(pw, null, sb.toString()); 169 cananian 1.1.2.1 } 170 cananian 1.1.2.1 } 171 cananian 1.1.2.1 /** Pretty-print a SIGMA. */ 172 cananian 1.1.2.1 static void indent(PrintWriter pw, SIGMA s) { 173 cananian 1.1.2.1 for (int i=0; i<s.numSigmas(); i++) { 174 cananian 1.1.2.1 StringBuffer sb = new StringBuffer(" <"); 175 cananian 1.1.2.1 for (int j=0; j<s.arity(); j++) { 176 cananian 1.1.2.1 sb.append(s.dst(i, j)); 177 cananian 1.1.2.1 if (j<s.arity()-1) sb.append(", "); 178 cananian 1.1.2.1 } 179 cananian 1.1.2.1 sb.append(">=sigma("); 180 cananian 1.1.2.1 sb.append(s.src(i)); 181 cananian 1.1.2.1 sb.append(")"); 182 cananian 1.1.2.1 indent(pw, null, sb.toString()); 183 cananian 1.1.2.1 } 184 cananian 1.1.2.1 } 185 cananian 1.1.2.1 186 cananian 1.1.2.1 //////////////////////////////////////////////////////////// 187 cananian 1.1.2.1 /** Pretty-print a string at the proper indentation. */ 188 cananian 1.1.2.1 static void indent(PrintWriter pw, HCodeElement src, String s) { 189 cananian 1.1.2.3 indent(pw, src, null, s); 190 cananian 1.1.2.1 } 191 cananian 1.1.2.1 /** Pretty-print a string and an optional label at the proper 192 cananian 1.1.2.1 * indentation.*/ 193 cananian 1.1.2.1 static void indent(PrintWriter pw, HCodeElement src, String l, String s) { 194 cananian 1.1.2.2 StringBuffer sb = new StringBuffer(); 195 cananian 1.1.2.1 if (src!=null) { 196 cananian 1.1.2.2 sb.append(":" + src.getLineNumber()); 197 cananian 1.1.2.2 String sf = src.getSourceFile(); 198 cananian 1.1.2.2 int n = fieldW1 - sb.length(); 199 cananian 1.1.2.2 n = (n<0)?0:(n>sf.length())?sf.length():n; 200 cananian 1.1.2.2 sb.insert(0, sf.substring(0,n)); 201 cananian 1.1.2.2 } 202 cananian 1.1.2.2 while (sb.length() <= fieldW1) sb.append(' '); 203 cananian 1.1.2.2 204 cananian 1.1.2.2 if (l!=null) sb.append(l); 205 cananian 1.1.2.2 while (sb.length() < (1+fieldW1+fieldW2)) sb.append(' '); 206 cananian 1.1.2.2 if (s!=null) sb.append(s); 207 cananian 1.1.2.2 208 cananian 1.1.2.2 pw.println(sb.toString()); 209 cananian 1.1.2.1 } 210 cananian 1.1.2.2 /** Width of the first (source file/line number) output field. */ 211 cananian 1.1.2.2 private static final int fieldW1 = 8; 212 cananian 1.1.2.2 /** Width of the second (label) output field. */ 213 cananian 1.1.2.2 private static final int fieldW2 = 5; 214 cananian 1.1.2.1 215 cananian 1.1.2.4 ///////// Handler Set utility functions. ////// 216 cananian 1.1.2.4 private static final HandlerSet handlers(final METHOD m, final Quad q) { 217 cananian 1.1.2.4 HandlerSet hs = null; 218 cananian 1.1.2.4 final Quad[] ql = m.next(); 219 cananian 1.1.2.4 for (int i=ql.length-1; i > 0; i--) // element 0 is not a HANDLER 220 cananian 1.1.2.4 if (((HANDLER)ql[i]).isProtected(q)) 221 cananian 1.1.2.4 hs = new HandlerSet((HANDLER)ql[i], hs); 222 cananian 1.1.2.4 return hs; 223 cananian 1.1.2.4 } 224 cananian 1.1.2.4 225 cananian 1.1.2.4 ///////// Inner classes /////////////////// 226 cananian 1.1.2.4 /** Label class. */ 227 cananian 1.1.2.4 private static final class Label { 228 cananian 1.1.2.1 int num = 0; 229 cananian 1.1.2.1 public void renumber(int n) { num = n; } 230 cananian 1.1.2.1 public String toString() { return "L"+num; } 231 cananian 1.1.2.1 } 232 cananian 1.2 }