comparison graal/com.oracle.max.graal.compiler/src/com/sun/c1x/debug/CFGPrinter.java @ 2872:0341b6424579

Project renaming.
author Thomas Wuerthinger <thomas@wuerthinger.net>
date Wed, 08 Jun 2011 08:42:25 +0200
parents graal/GraalCompiler/src/com/sun/c1x/debug/CFGPrinter.java@2af109bec0c0
children
comparison
equal deleted inserted replaced
2871:d704eb526603 2872:0341b6424579
1 /*
2 * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23 package com.sun.c1x.debug;
24
25 import java.io.*;
26 import java.util.*;
27
28 import com.oracle.graal.graph.*;
29 import com.oracle.max.graal.schedule.*;
30 import com.sun.c1x.*;
31 import com.sun.c1x.alloc.*;
32 import com.sun.c1x.alloc.Interval.*;
33 import com.sun.c1x.graph.*;
34 import com.sun.c1x.ir.*;
35 import com.sun.c1x.lir.*;
36 import com.sun.c1x.lir.LIRInstruction.*;
37 import com.sun.c1x.util.*;
38 import com.sun.c1x.value.*;
39 import com.sun.cri.ci.*;
40 import com.sun.cri.ci.CiAddress.*;
41 import com.sun.cri.ri.*;
42
43 /**
44 * Utility for printing the control flow graph of a method being compiled by C1X at various compilation phases.
45 * The output format matches that produced by HotSpot so that it can then be fed to the
46 * <a href="https://c1visualizer.dev.java.net/">C1 Visualizer</a>.
47 */
48 public class CFGPrinter {
49 private static final String COLUMN_END = " <|@";
50 private static final String HOVER_START = "<@";
51 private static final String HOVER_SEP = "|@";
52 private static final String HOVER_END = ">@";
53
54 private static OutputStream cfgFileStream;
55
56 /**
57 * Gets the output stream on the file "output.cfg" in the current working directory.
58 * This stream is first opened if necessary.
59 *
60 * @return the output stream to "output.cfg" or {@code null} if there was an error opening this file for writing
61 */
62 public static synchronized OutputStream cfgFileStream() {
63 if (cfgFileStream == null) {
64 File cfgFile = new File("output.cfg");
65 try {
66 cfgFileStream = new FileOutputStream(cfgFile);
67 } catch (FileNotFoundException e) {
68 TTY.println("WARNING: Could not open " + cfgFile.getAbsolutePath());
69 }
70 }
71 return cfgFileStream;
72 }
73
74 private final LogStream out;
75 private final CiTarget target;
76
77 /**
78 * Creates a control flow graph printer.
79 *
80 * @param os where the output generated via this printer shown be written
81 * @param target the target architecture description
82 */
83 public CFGPrinter(OutputStream os, CiTarget target) {
84 out = new LogStream(os);
85 this.target = target;
86 }
87
88 /**
89 * Flushes all buffered output to the stream passed to {@link #CFGPrinter(OutputStream, CiTarget)}.
90 */
91 public void flush() {
92 out.flush();
93 }
94
95 private void begin(String string) {
96 out.println("begin_" + string);
97 out.adjustIndentation(2);
98 }
99
100 private void end(String string) {
101 out.adjustIndentation(-2);
102 out.println("end_" + string);
103 }
104
105 /**
106 * Prints a compilation timestamp for a given method.
107 *
108 * @param method the method for which a timestamp will be printed
109 */
110 public void printCompilation(RiMethod method) {
111 begin("compilation");
112 out.print("name \" ").print(CiUtil.format("%H::%n", method, true)).println('"');
113 out.print("method \"").print(CiUtil.format("%f %r %H.%n(%p)", method, true)).println('"');
114 out.print("date ").println(System.currentTimeMillis());
115 end("compilation");
116 }
117
118 /**
119 * Print the details of a given control flow graph block.
120 *
121 * @param block the block to print
122 * @param successors the successor blocks of {@code block}
123 * @param handlers the exception handler blocks of {@code block}
124 * @param printHIR if {@code true} the HIR for each instruction in the block will be printed
125 * @param printLIR if {@code true} the LIR for each instruction in the block will be printed
126 */
127 void printBlock(Block block, List<Block> successors, Block handler, boolean printHIR, boolean printLIR) {
128 begin("block");
129
130 out.print("name \"B").print(block.blockID()).println('"');
131 out.print("from_bci -1");
132 out.print("to_bci -1");
133
134 out.print("predecessors ");
135 for (Block pred : block.getPredecessors()) {
136 out.print("\"B").print(pred.blockID()).print("\" ");
137 }
138 out.println();
139
140 out.print("successors ");
141 for (Block succ : successors) {
142 out.print("\"B").print(succ.blockID()).print("\" ");
143 }
144 out.println();
145
146 out.print("xhandlers");
147 if (handler != null) {
148 out.print("\"B").print(handler.blockID()).print("\" ");
149 }
150 out.println();
151
152 out.print("flags ");
153 out.println();
154
155 out.print("loop_index ").println(-1);
156 out.print("loop_depth ").println(-1);
157
158 if (printHIR) {
159 printHIR(block);
160 }
161
162 // TODO(tw): Add possibility to print LIR.
163 //if (printLIR) {
164 // printLIR(block.lirBlock());
165 //}
166
167 end("block");
168 }
169
170 /**
171 * Prints the JVM frame state upon entry to a given block.
172 *
173 * @param block the block for which the frame state is to be printed
174 */
175 /*private void printState(Block block) {
176 begin("states");
177
178 FrameState state = block.stateBefore();
179 if (state == null) {
180 return;
181 }
182 int stackSize = state.stackSize();
183 if (stackSize > 0) {
184 begin("stack");
185 out.print("size ").println(stackSize);
186 out.print("method \"").print(CiUtil.toLocation(C1XCompilation.compilation().method, state.bci)).println('"');
187
188 int i = 0;
189 while (i < stackSize) {
190 Value value = state.stackAt(i);
191 out.disableIndentation();
192 out.print(block.stateString(i, value));
193 printOperand(value);
194 out.println();
195 out.enableIndentation();
196 if (value == null) {
197 i++;
198 } else {
199 i += value.kind.sizeInSlots();
200 }
201 }
202 end("stack");
203 }
204
205 if (state.locksSize() > 0) {
206 begin("locks");
207 out.print("size ").println(state.locksSize());
208 out.print("method \"").print(CiUtil.toLocation(C1XCompilation.compilation().method, state.bci)).println('"');
209
210 for (int i = 0; i < state.locksSize(); ++i) {
211 Value value = state.lockAt(i);
212 out.disableIndentation();
213 out.print(block.stateString(i, value));
214 printOperand(value);
215 out.println();
216 out.enableIndentation();
217 }
218 end("locks");
219 }
220
221 begin("locals");
222 out.print("size ").println(state.localsSize());
223 out.print("method \"").print(CiUtil.toLocation(C1XCompilation.compilation().method, state.bci)).println('"');
224 int i = 0;
225 while (i < state.localsSize()) {
226 Value value = state.localAt(i);
227 if (value != null) {
228 out.disableIndentation();
229 out.print(block.stateString(i, value));
230 printOperand(value);
231 out.println();
232 out.enableIndentation();
233 // also ignore illegal HiWords
234 i += value.isIllegal() ? 1 : value.kind.sizeInSlots();
235 } else {
236 i++;
237 }
238 }
239 end("locals");
240 end("states");
241 }*/
242
243 /**
244 * Formats a given {@linkplain FrameState JVM frame state} as a multi line string.
245 */
246 private String stateToString(FrameState state, CFGOperandFormatter operandFmt) {
247 if (state == null) {
248 return null;
249 }
250
251 StringBuilder buf = new StringBuilder();
252 buf.append(CiUtil.toLocation(C1XCompilation.compilation().method, state.bci));
253 buf.append('\n');
254 if (state.stackSize() > 0) {
255 int i = 0;
256 buf.append("stack: ");
257 while (i < state.stackSize()) {
258 if (i == 0) {
259 buf.append(' ');
260 }
261 Value value = state.stackAt(i);
262 buf.append(stateValueToString(value, operandFmt)).append(' ');
263 i++;
264 }
265 buf.append("\n");
266 }
267
268 if (state.locksSize() > 0) {
269 buf.append("locks: ");
270 for (int i = 0; i < state.locksSize(); ++i) {
271 if (i == 0) {
272 buf.append(' ');
273 }
274 Value value = state.lockAt(i);
275 buf.append(stateValueToString(value, operandFmt)).append(' ');
276 }
277 buf.append("\n");
278 }
279
280 buf.append("locals: ");
281 int i = 0;
282 while (i < state.localsSize()) {
283 if (i == 0) {
284 buf.append(' ');
285 }
286 Value value = state.localAt(i);
287 buf.append(stateValueToString(value, operandFmt)).append(' ');
288 i++;
289 }
290 buf.append("\n");
291 return buf.toString();
292 }
293
294 private String stateValueToString(Value value, OperandFormatter operandFmt) {
295 if (operandFmt == null) {
296 return Util.valueString(value);
297 }
298 if (value == null) {
299 return "-";
300 }
301 return operandFmt.format(value.operand());
302 }
303
304 private String stateValueToString(CiValue value, OperandFormatter operandFmt) {
305 if (value == null) {
306 return "-";
307 }
308 return operandFmt.format(value);
309 }
310
311 /**
312 * Formats a given {@linkplain FrameState JVM frame state} as a multi line string.
313 */
314 private String debugInfoToString(CiDebugInfo info, CFGOperandFormatter operandFmt) {
315 if (info == null) {
316 return null;
317 }
318 StringBuilder sb = new StringBuilder();
319
320
321 if (info.hasRegisterRefMap()) {
322 sb.append("reg-ref-map:");
323 C1XCompilation compilation = C1XCompilation.compilation();
324 CiArchitecture arch = compilation == null ? null : compilation.target.arch;
325 for (int reg = info.registerRefMap.nextSetBit(0); reg >= 0; reg = info.registerRefMap.nextSetBit(reg + 1)) {
326 sb.append(' ').append(arch == null ? "reg" + reg : arch.registers[reg]);
327 }
328 sb.append("\n");
329 }
330 if (info.hasStackRefMap()) {
331 sb.append("frame-ref-map:");
332 CiBitMap bm = info.frameRefMap;
333 for (int i = bm.nextSetBit(0); i >= 0; i = bm.nextSetBit(i + 1)) {
334 sb.append(' ').append(CiStackSlot.get(CiKind.Object, i));
335 }
336 sb.append("\n");
337 }
338 if (info.codePos != null) {
339 sb.append(stateToString(info.codePos, operandFmt));
340 }
341 return sb.toString();
342 }
343
344 /**
345 * Formats a given {@linkplain FrameState JVM frame state} as a multi line string.
346 */
347 private String stateToString(CiCodePos codePos, CFGOperandFormatter operandFmt) {
348 if (codePos == null) {
349 return null;
350 }
351
352 StringBuilder buf = new StringBuilder();
353
354 do {
355 buf.append(CiUtil.toLocation(codePos.method, codePos.bci));
356 buf.append('\n');
357 if (codePos instanceof CiFrame) {
358 CiFrame frame = (CiFrame) codePos;
359 if (frame.numStack > 0) {
360 int i = 0;
361 buf.append("stack: ");
362 while (i < frame.numStack) {
363 if (i == 0) {
364 buf.append(' ');
365 }
366 CiValue value = frame.getStackValue(i);
367 buf.append(stateValueToString(value, operandFmt)).append(' ');
368 i++;
369 }
370 buf.append("\n");
371 }
372
373 if (frame.numLocks > 0) {
374 buf.append("locks: ");
375 for (int i = 0; i < frame.numLocks; ++i) {
376 if (i == 0) {
377 buf.append(' ');
378 }
379 CiValue value = frame.getLockValue(i);
380 buf.append(stateValueToString(value, operandFmt)).append(' ');
381 }
382 buf.append("\n");
383 }
384
385 buf.append("locals: ");
386 int i = 0;
387 while (i < frame.numLocals) {
388 if (i == 0) {
389 buf.append(' ');
390 }
391 CiValue value = frame.getLocalValue(i);
392 buf.append(stateValueToString(value, operandFmt)).append(' ');
393 i++;
394 }
395 buf.append("\n");
396 }
397 codePos = codePos.caller;
398 } while (codePos != null);
399 return buf.toString();
400 }
401
402 /**
403 * Prints the HIR for each instruction in a given block.
404 *
405 * @param block
406 */
407 private void printHIR(Block block) {
408 begin("IR");
409 out.println("HIR");
410 out.disableIndentation();
411 for (Node i : block.getInstructions()) {
412 if (i instanceof Instruction) {
413 printInstructionHIR((Instruction) i);
414 }
415 }
416 out.enableIndentation();
417 end("IR");
418 }
419
420 /**
421 * Formats LIR operands as expected by the C1 Visualizer.
422 */
423 public static class CFGOperandFormatter extends OperandFormatter {
424 /**
425 * The textual delimiters used for an operand depend on the context in which it is being
426 * printed. When printed as part of a frame state or as the result operand in a HIR node listing,
427 * it is enclosed in double-quotes (i.e. {@code "}'s).
428 */
429 public final boolean asStateOrHIROperandResult;
430
431 public CFGOperandFormatter(boolean asStateOrHIROperandResult) {
432 this.asStateOrHIROperandResult = asStateOrHIROperandResult;
433 }
434
435 @Override
436 public String format(CiValue operand) {
437 if (operand.isLegal()) {
438 String op;
439 if (operand.isVariableOrRegister() || operand.isStackSlot()) {
440 op = operand.name();
441 } else if (operand.isConstant()) {
442 CiConstant constant = (CiConstant) operand;
443 op = operand.kind.javaName + ":" + operand.kind.format(constant.boxedValue());
444 } else if (operand.isAddress()) {
445 CiAddress address = (CiAddress) operand;
446 op = "Base:" + format(address.base);
447 if (!address.index.isIllegal()) {
448 op += " Index:" + format(address.index);
449 }
450 if (address.scale != Scale.Times1) {
451 op += " * " + address.scale.value;
452 }
453 op += " Disp:" + address.displacement;
454 } else {
455 assert operand.isIllegal();
456 op = "-";
457 }
458 if (operand.kind != CiKind.Illegal) {
459 op += "|" + operand.kind.typeChar;
460 }
461 if (asStateOrHIROperandResult) {
462 op = " \"" + op.replace('"', '\'') + "\" ";
463 }
464 return op;
465 }
466 return "";
467 }
468 }
469
470 /**
471 * Prints the LIR for each instruction in a given block.
472 *
473 * @param block the block to print
474 */
475 private void printLIR(LIRBlock block) {
476 LIRList lir = block.lir();
477 if (lir != null) {
478 begin("IR");
479 out.println("LIR");
480 for (int i = 0; i < lir.length(); i++) {
481 LIRInstruction inst = lir.at(i);
482 out.printf("nr %4d ", inst.id).print(COLUMN_END);
483
484 if (inst.info != null) {
485 int level = out.indentationLevel();
486 out.adjustIndentation(-level);
487 String state;
488 if (inst.info.debugInfo != null) {
489 // Use register-allocator output if available
490 state = debugInfoToString(inst.info.debugInfo, new CFGOperandFormatter(false));
491 } else {
492 state = stateToString(inst.info.state, new CFGOperandFormatter(false));
493 }
494 if (state != null) {
495 out.print(" st ").print(HOVER_START).print("st").print(HOVER_SEP).print(state).print(HOVER_END).print(COLUMN_END);
496 }
497 out.adjustIndentation(level);
498 }
499
500 out.print(" instruction ").print(inst.toString(new CFGOperandFormatter(false))).print(COLUMN_END);
501 out.println(COLUMN_END);
502 }
503 end("IR");
504 }
505 }
506
507 private void printOperand(Value i) {
508 if (i != null && i.operand().isLegal()) {
509 out.print(new CFGOperandFormatter(true).format(i.operand()));
510 }
511 }
512
513 /**
514 * Prints the HIR for a given instruction.
515 *
516 * @param i the instruction for which HIR will be printed
517 */
518 private void printInstructionHIR(Instruction i) {
519 out.print("bci ").print(-1).println(COLUMN_END);
520 if (i.operand().isLegal()) {
521 out.print("result ").print(new CFGOperandFormatter(false).format(i.operand())).println(COLUMN_END);
522 }
523 out.print("tid ").print(i).println(COLUMN_END);
524
525 String state = stateToString(i.stateAfter(), null);
526 if (state != null) {
527 out.print("st ").print(HOVER_START).print("st").print(HOVER_SEP).print(state).print(HOVER_END).println(COLUMN_END);
528 }
529
530 out.print("instruction ");
531 i.print(out);
532 out.print(COLUMN_END).print(' ').println(COLUMN_END);
533 }
534
535 /**
536 * Prints the control flow graph denoted by a given block map.
537 *
538 * @param blockMap a data structure describing the blocks in a method and how they are connected
539 * @param codeSize the bytecode size of the method from which {@code blockMap} was produced
540 * @param label a label describing the compilation phase that produced the control flow graph
541 * @param printHIR if {@code true} the HIR for each instruction in the block will be printed
542 * @param printLIR if {@code true} the LIR for each instruction in the block will be printed
543 */
544 public void printCFG(RiMethod method, BlockMap blockMap, int codeSize, String label, boolean printHIR, boolean printLIR) {
545 begin("cfg");
546 out.print("name \"").print(label).println('"');
547 for (BlockMap.Block block : blockMap.blocks) {
548 begin("block");
549 blockMap.printBlock(block, out);
550 end("block");
551 }
552 end("cfg");
553 }
554
555 /**
556 * Prints the control flow graph rooted at a given block.
557 *
558 * @param startBlock the entry block of the control flow graph to be printed
559 * @param label a label describing the compilation phase that produced the control flow graph
560 * @param printHIR if {@code true} the HIR for each instruction in the block will be printed
561 * @param printLIR if {@code true} the LIR for each instruction in the block will be printed
562 */
563 public void printCFG(Block startBlock, String label, final boolean printHIR, final boolean printLIR) {
564 begin("cfg");
565 out.print("name \"").print(label).println('"');
566 startBlock.iteratePreOrder(new BlockClosure() {
567 public void apply(Block block) {
568 List<Block> successors = block.getSuccessors();
569 printBlock(block, successors, null, printHIR, printLIR);
570 }
571 });
572 end("cfg");
573 }
574
575 public void printIntervals(LinearScan allocator, Interval[] intervals, String name) {
576 begin("intervals");
577 out.println(String.format("name \"%s\"", name));
578
579 for (Interval interval : intervals) {
580 if (interval != null) {
581 printInterval(allocator, interval);
582 }
583 }
584
585 end("intervals");
586 }
587
588 private void printInterval(LinearScan allocator, Interval interval) {
589 out.printf("%d %s ", interval.operandNumber, (interval.operand.isRegister() ? "fixed" : interval.kind().name()));
590 if (interval.operand.isRegister()) {
591 out.printf("\"[%s|%c]\"", interval.operand.name(), interval.operand.kind.typeChar);
592 } else {
593 if (interval.location() != null) {
594 out.printf("\"[%s|%c]\"", interval.location().name(), interval.location().kind.typeChar);
595 }
596 }
597
598 Interval hint = interval.locationHint(false, allocator);
599 out.printf("%d %d ", interval.splitParent().operandNumber, hint != null ? hint.operandNumber : -1);
600
601 // print ranges
602 Range cur = interval.first();
603 while (cur != Range.EndMarker) {
604 out.printf("[%d, %d[", cur.from, cur.to);
605 cur = cur.next;
606 assert cur != null : "range list not closed with range sentinel";
607 }
608
609 // print use positions
610 int prev = 0;
611 UsePosList usePosList = interval.usePosList();
612 for (int i = usePosList.size() - 1; i >= 0; --i) {
613 assert prev < usePosList.usePos(i) : "use positions not sorted";
614 out.printf("%d %s ", usePosList.usePos(i), usePosList.registerPriority(i));
615 prev = usePosList.usePos(i);
616 }
617
618 out.printf(" \"%s\"", interval.spillState());
619 out.println();
620 }
621
622 public void printMachineCode(String code, String label) {
623 if (code.length() == 0) {
624 return;
625 }
626 if (label != null) {
627 begin("cfg");
628 out.print("name \"").print(label).println('"');
629 end("cfg");
630 }
631 begin("nmethod");
632 out.print(code);
633 out.println(" <|@");
634 end("nmethod");
635 }
636 }