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      }