1 /* 2 * Copyright (c) 2009, 2015, 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 24 25 package org.graalvm.compiler.printer; 26 27 import static java.lang.Character.toLowerCase; 28 29 import java.io.OutputStream; 30 import java.util.ArrayList; 31 import java.util.Arrays; 32 import java.util.BitSet; 33 import java.util.Iterator; 34 import java.util.List; 35 import java.util.Map; 36 import java.util.TreeMap; 37 38 import jdk.internal.vm.compiler.collections.UnmodifiableMapCursor; 39 import org.graalvm.compiler.bytecode.Bytecode; 40 import org.graalvm.compiler.bytecode.BytecodeDisassembler; 41 import org.graalvm.compiler.core.common.alloc.Trace; 42 import org.graalvm.compiler.core.common.alloc.TraceBuilderResult; 43 import org.graalvm.compiler.core.common.cfg.AbstractBlockBase; 44 import org.graalvm.compiler.core.common.cfg.AbstractControlFlowGraph; 45 import org.graalvm.compiler.core.gen.NodeLIRBuilder; 46 import org.graalvm.compiler.graph.Node; 47 import org.graalvm.compiler.graph.NodeBitMap; 48 import org.graalvm.compiler.graph.NodeMap; 49 import org.graalvm.compiler.graph.Position; 50 import org.graalvm.compiler.java.BciBlockMapping; 51 import org.graalvm.compiler.lir.LIR; 52 import org.graalvm.compiler.lir.LIRInstruction; 53 import org.graalvm.compiler.lir.alloc.trace.GlobalLivenessInfo; 54 import org.graalvm.compiler.lir.debug.IntervalDumper; 55 import org.graalvm.compiler.lir.debug.IntervalDumper.IntervalVisitor; 56 import org.graalvm.compiler.lir.gen.LIRGenerationResult; 57 import org.graalvm.compiler.nodeinfo.Verbosity; 58 import org.graalvm.compiler.nodes.AbstractBeginNode; 59 import org.graalvm.compiler.nodes.AbstractEndNode; 60 import org.graalvm.compiler.nodes.AbstractMergeNode; 61 import org.graalvm.compiler.nodes.FixedNode; 62 import org.graalvm.compiler.nodes.FixedWithNextNode; 63 import org.graalvm.compiler.nodes.FrameState; 64 import org.graalvm.compiler.nodes.PhiNode; 65 import org.graalvm.compiler.nodes.StateSplit; 66 import org.graalvm.compiler.nodes.StructuredGraph.ScheduleResult; 67 import org.graalvm.compiler.nodes.ValueNode; 68 import org.graalvm.compiler.nodes.ValuePhiNode; 69 import org.graalvm.compiler.nodes.calc.FloatingNode; 70 import org.graalvm.compiler.nodes.cfg.Block; 71 import org.graalvm.compiler.nodes.cfg.ControlFlowGraph; 72 73 import jdk.vm.ci.code.DebugInfo; 74 import jdk.vm.ci.code.TargetDescription; 75 import jdk.vm.ci.meta.JavaKind; 76 import jdk.vm.ci.meta.ResolvedJavaMethod; 77 import jdk.vm.ci.meta.Value; 78 79 /** 80 * Utility for printing Graal IR at various compilation phases. 81 */ 82 class CFGPrinter extends CompilationPrinter { 83 84 protected TargetDescription target; 85 protected LIR lir; 86 protected NodeLIRBuilder nodeLirGenerator; 87 protected ControlFlowGraph cfg; 88 protected ScheduleResult schedule; 89 protected ResolvedJavaMethod method; 90 protected GlobalLivenessInfo livenessInfo; 91 protected LIRGenerationResult res; 92 93 /** 94 * Creates a control flow graph printer. 95 * 96 * @param out where the output generated via this printer shown be written 97 */ 98 CFGPrinter(OutputStream out) { 99 super(out); 100 } 101 102 /** 103 * Prints the control flow graph denoted by a given block map. 104 * 105 * @param label A label describing the compilation phase that produced the control flow graph. 106 * @param blockMap A data structure describing the blocks in a method and how they are 107 * connected. 108 */ 109 public void printCFG(String label, BciBlockMapping blockMap) { 110 begin("cfg"); 111 out.print("name \"").print(label).println('"'); 112 for (BciBlockMapping.BciBlock block : blockMap.getBlocks()) { 113 begin("block"); 114 printBlock(block); 115 end("block"); 116 } 117 end("cfg"); 118 } 119 120 private void printBlock(BciBlockMapping.BciBlock block) { 121 out.print("name \"B").print(block.getStartBci()).println('"'); 122 out.print("from_bci ").println(block.getStartBci()); 123 out.print("to_bci ").println(block.getEndBci()); 124 125 out.println("predecessors "); 126 127 out.print("successors "); 128 for (BciBlockMapping.BciBlock succ : block.getSuccessors()) { 129 if (!succ.isExceptionEntry()) { 130 out.print("\"B").print(succ.getStartBci()).print("\" "); 131 } 132 } 133 out.println(); 134 135 out.print("xhandlers"); 136 for (BciBlockMapping.BciBlock succ : block.getSuccessors()) { 137 if (succ.isExceptionEntry()) { 138 out.print("\"B").print(succ.getStartBci()).print("\" "); 139 } 140 } 141 out.println(); 142 143 out.print("flags "); 144 if (block.isExceptionEntry()) { 145 out.print("\"ex\" "); 146 } 147 if (block.isLoopHeader()) { 148 out.print("\"plh\" "); 149 } 150 out.println(); 151 152 out.print("loop_depth ").println(Long.bitCount(block.getLoops())); 153 } 154 155 private NodeMap<Block> latestScheduling; 156 private NodeBitMap printedNodes; 157 158 private boolean inFixedSchedule(Node node) { 159 return lir != null || schedule != null || node.isDeleted() || cfg.getNodeToBlock().get(node) != null; 160 } 161 162 /** 163 * Prints the specified list of blocks. 164 * 165 * @param label A label describing the compilation phase that produced the control flow graph. 166 * @param blocks The list of blocks to be printed. 167 */ 168 public void printCFG(String label, AbstractBlockBase<?>[] blocks, boolean printNodes) { 169 if (lir == null) { 170 latestScheduling = new NodeMap<>(cfg.getNodeToBlock()); 171 for (AbstractBlockBase<?> abstractBlock : blocks) { 172 if (abstractBlock == null) { 173 continue; 174 } 175 Block block = (Block) abstractBlock; 176 Node cur = block.getBeginNode(); 177 while (true) { 178 assert inFixedSchedule(cur) && latestScheduling.get(cur) == block; 179 scheduleInputs(cur, block); 180 181 if (cur == block.getEndNode()) { 182 break; 183 } 184 assert cur.successors().count() == 1; 185 cur = cur.successors().first(); 186 } 187 } 188 } 189 190 begin("cfg"); 191 out.print("name \"").print(label).println('"'); 192 for (AbstractBlockBase<?> block : blocks) { 193 printBlock(block, printNodes); 194 } 195 end("cfg"); 196 // NOTE: we do this only because the c1visualizer does not recognize the bytecode block if 197 // it is proceeding the cfg blocks. Currently we have no direct influence on the emit order. 198 // As a workaround we dump the bytecode after every cfg. 199 if (method != null) { 200 printBytecodes(new BytecodeDisassembler(false).disassemble(method)); 201 } 202 203 latestScheduling = null; 204 } 205 206 private void scheduleInputs(Node node, Block nodeBlock) { 207 if (node instanceof ValuePhiNode) { 208 PhiNode phi = (PhiNode) node; 209 Block phiBlock = latestScheduling.get(phi.merge()); 210 assert phiBlock != null; 211 for (Block pred : phiBlock.getPredecessors()) { 212 schedule(phi.valueAt((AbstractEndNode) pred.getEndNode()), pred); 213 } 214 215 } else { 216 for (Node input : node.inputs()) { 217 schedule(input, nodeBlock); 218 } 219 } 220 } 221 222 private void schedule(Node input, Block block) { 223 if (!inFixedSchedule(input)) { 224 Block inputBlock = block; 225 if (latestScheduling.get(input) != null) { 226 inputBlock = AbstractControlFlowGraph.commonDominatorTyped(inputBlock, latestScheduling.get(input)); 227 } 228 if (inputBlock != latestScheduling.get(input)) { 229 latestScheduling.set(input, inputBlock); 230 scheduleInputs(input, inputBlock); 231 } 232 } 233 } 234 235 private void printBlock(AbstractBlockBase<?> block, boolean printNodes) { 236 if (block == null) { 237 return; 238 } 239 printBlockProlog(block); 240 if (printNodes) { 241 assert block instanceof Block; 242 printNodes((Block) block); 243 } 244 printBlockEpilog(block); 245 } 246 247 private void printBlockEpilog(AbstractBlockBase<?> block) { 248 printLIR(block); 249 end("block"); 250 } 251 252 private void printBlockProlog(AbstractBlockBase<?> block) { 253 begin("block"); 254 255 out.print("name \"").print(blockToString(block)).println('"'); 256 out.println("from_bci -1"); 257 out.println("to_bci -1"); 258 259 out.print("predecessors "); 260 for (AbstractBlockBase<?> pred : block.getPredecessors()) { 261 out.print("\"").print(blockToString(pred)).print("\" "); 262 } 263 out.println(); 264 265 out.print("successors "); 266 for (AbstractBlockBase<?> succ : block.getSuccessors()) { 267 if (!succ.isExceptionEntry()) { 268 out.print("\"").print(blockToString(succ)).print("\" "); 269 } 270 } 271 out.println(); 272 273 out.print("xhandlers"); 274 for (AbstractBlockBase<?> succ : block.getSuccessors()) { 275 if (succ.isExceptionEntry()) { 276 out.print("\"").print(blockToString(succ)).print("\" "); 277 } 278 } 279 out.println(); 280 281 out.print("flags "); 282 if (block.isLoopHeader()) { 283 out.print("\"llh\" "); 284 } 285 if (block.isLoopEnd()) { 286 out.print("\"lle\" "); 287 } 288 if (block.isExceptionEntry()) { 289 out.print("\"ex\" "); 290 } 291 out.println(); 292 293 if (block.getLoop() != null) { 294 out.print("loop_index ").println(block.getLoop().getIndex()); 295 out.print("loop_depth ").println(block.getLoop().getDepth()); 296 } 297 298 out.print("probability ").println(Double.doubleToRawLongBits(block.getRelativeFrequency())); 299 } 300 301 private void printNodes(Block block) { 302 printedNodes = new NodeBitMap(cfg.graph); 303 begin("IR"); 304 out.println("HIR"); 305 out.disableIndentation(); 306 307 if (block.getBeginNode() instanceof AbstractMergeNode) { 308 // Currently phi functions are not in the schedule, so print them separately here. 309 for (ValueNode phi : ((AbstractMergeNode) block.getBeginNode()).phis()) { 310 printNode(phi, false); 311 } 312 } 313 314 Node cur = block.getBeginNode(); 315 while (true) { 316 printNode(cur, false); 317 318 if (cur == block.getEndNode()) { 319 UnmodifiableMapCursor<Node, Block> cursor = latestScheduling.getEntries(); 320 while (cursor.advance()) { 321 if (cursor.getValue() == block && !inFixedSchedule(cursor.getKey()) && !printedNodes.isMarked(cursor.getKey())) { 322 printNode(cursor.getKey(), true); 323 } 324 } 325 break; 326 } 327 assert cur.successors().count() == 1; 328 cur = cur.successors().first(); 329 } 330 331 out.enableIndentation(); 332 end("IR"); 333 printedNodes = null; 334 } 335 336 private void printNode(Node node, boolean unscheduled) { 337 assert !printedNodes.isMarked(node); 338 printedNodes.mark(node); 339 340 if (!(node instanceof ValuePhiNode)) { 341 for (Node input : node.inputs()) { 342 if (!inFixedSchedule(input) && !printedNodes.isMarked(input)) { 343 printNode(input, true); 344 } 345 } 346 } 347 348 if (unscheduled) { 349 assert lir == null && schedule == null : "unscheduled nodes can only be present before LIR generation"; 350 out.print("f ").print(HOVER_START).print("u").print(HOVER_SEP).print("unscheduled").print(HOVER_END).println(COLUMN_END); 351 } else if (node instanceof FixedWithNextNode) { 352 out.print("f ").print(HOVER_START).print("#").print(HOVER_SEP).print("fixed with next").print(HOVER_END).println(COLUMN_END); 353 } else if (node instanceof FixedNode) { 354 out.print("f ").print(HOVER_START).print("*").print(HOVER_SEP).print("fixed").print(HOVER_END).println(COLUMN_END); 355 } else if (node instanceof FloatingNode) { 356 out.print("f ").print(HOVER_START).print("~").print(HOVER_SEP).print("floating").print(HOVER_END).println(COLUMN_END); 357 } 358 out.print("tid ").print(nodeToString(node)).println(COLUMN_END); 359 360 if (nodeLirGenerator != null) { 361 Value operand = nodeLirGenerator.hasOperand(node) ? nodeLirGenerator.operand(node) : null; 362 if (operand != null) { 363 out.print("result ").print(operand.toString()).println(COLUMN_END); 364 } 365 } 366 367 if (node instanceof StateSplit) { 368 StateSplit stateSplit = (StateSplit) node; 369 if (stateSplit.stateAfter() != null) { 370 String state = stateToString(stateSplit.stateAfter()); 371 out.print("st ").print(HOVER_START).print("st").print(HOVER_SEP).print(state).print(HOVER_END).println(COLUMN_END); 372 } 373 } 374 375 Map<Object, Object> props = new TreeMap<>(node.getDebugProperties()); 376 out.print("d ").print(HOVER_START).print("d").print(HOVER_SEP); 377 out.println("=== Debug Properties ==="); 378 for (Map.Entry<Object, Object> entry : props.entrySet()) { 379 out.print(entry.getKey().toString()).print(": ").print(entry.getValue() == null ? "[null]" : entry.getValue().toString()).println(); 380 } 381 out.println("=== Inputs ==="); 382 printNamedNodes(node, node.inputPositions().iterator(), "", "\n", null); 383 out.println("=== Succesors ==="); 384 printNamedNodes(node, node.successorPositions().iterator(), "", "\n", null); 385 out.println("=== Usages ==="); 386 if (!node.hasNoUsages()) { 387 for (Node usage : node.usages()) { 388 out.print(nodeToString(usage)).print(" "); 389 } 390 out.println(); 391 } 392 out.println("=== Predecessor ==="); 393 out.print(nodeToString(node.predecessor())).print(" "); 394 out.print(HOVER_END).println(COLUMN_END); 395 396 out.print("instruction "); 397 out.print(HOVER_START).print(node.getNodeClass().shortName()).print(HOVER_SEP).print(node.getClass().getName()).print(HOVER_END).print(" "); 398 printNamedNodes(node, node.inputPositions().iterator(), "", "", "#NDF"); 399 printNamedNodes(node, node.successorPositions().iterator(), "#", "", "#NDF"); 400 for (Map.Entry<Object, Object> entry : props.entrySet()) { 401 String key = entry.getKey().toString(); 402 if (key.startsWith("data.") && !key.equals("data.stamp")) { 403 out.print(key.substring("data.".length())).print(": ").print(entry.getValue() == null ? "[null]" : entry.getValue().toString()).print(" "); 404 } 405 } 406 out.print(COLUMN_END).print(' ').println(COLUMN_END); 407 } 408 409 private void printNamedNodes(Node node, Iterator<Position> iter, String prefix, String suffix, String hideSuffix) { 410 int lastIndex = -1; 411 while (iter.hasNext()) { 412 Position pos = iter.next(); 413 if (hideSuffix != null && pos.getName().endsWith(hideSuffix)) { 414 continue; 415 } 416 417 if (pos.getIndex() != lastIndex) { 418 if (lastIndex != -1) { 419 out.print(suffix); 420 } 421 out.print(prefix).print(pos.getName()).print(": "); 422 lastIndex = pos.getIndex(); 423 } 424 out.print(nodeToString(pos.get(node))).print(" "); 425 } 426 if (lastIndex != -1) { 427 out.print(suffix); 428 } 429 } 430 431 private String stateToString(FrameState state) { 432 StringBuilder buf = new StringBuilder(); 433 FrameState curState = state; 434 do { 435 buf.append(Bytecode.toLocation(curState.getCode(), curState.bci)).append('\n'); 436 437 if (curState.stackSize() > 0) { 438 buf.append("stack: "); 439 for (int i = 0; i < curState.stackSize(); i++) { 440 buf.append(stateValueToString(curState.stackAt(i))).append(' '); 441 } 442 buf.append("\n"); 443 } 444 445 buf.append("locals: "); 446 for (int i = 0; i < curState.localsSize(); i++) { 447 buf.append(stateValueToString(curState.localAt(i))).append(' '); 448 } 449 buf.append("\n"); 450 451 buf.append("locks: "); 452 for (int i = 0; i < curState.locksSize(); i++) { 453 buf.append(stateValueToString(curState.lockAt(i))).append(' '); 454 } 455 buf.append("\n"); 456 457 curState = curState.outerFrameState(); 458 } while (curState != null); 459 460 return buf.toString(); 461 } 462 463 private String stateValueToString(ValueNode value) { 464 String result = nodeToString(value); 465 if (nodeLirGenerator != null && value != null && nodeLirGenerator.hasOperand(value)) { 466 Value operand = nodeLirGenerator.operand(value); 467 assert operand != null; 468 result += ": " + operand; 469 } 470 return result; 471 } 472 473 /** 474 * Prints the LIR for each instruction in a given block. 475 * 476 * @param block the block to print 477 */ 478 private void printLIR(AbstractBlockBase<?> block) { 479 if (lir == null) { 480 return; 481 } 482 ArrayList<LIRInstruction> lirInstructions = lir.getLIRforBlock(block); 483 if (lirInstructions == null) { 484 return; 485 } 486 487 begin("IR"); 488 out.println("LIR"); 489 490 if (livenessInfo != null) { 491 int opId = lirInstructions.get(0).id(); 492 printLiveVars(livenessInfo.getBlockIn(block), "in(var)", opId); 493 printLiveLoc(livenessInfo.getInLocation(block), "in(loc)", opId); 494 } 495 for (int i = 0; i < lirInstructions.size(); i++) { 496 LIRInstruction inst = lirInstructions.get(i); 497 printLIRInstruction(inst); 498 } 499 if (livenessInfo != null) { 500 int opId = lirInstructions.get(lirInstructions.size() - 1).id(); 501 printLiveVars(livenessInfo.getBlockOut(block), "out(var)", opId); 502 printLiveLoc(livenessInfo.getOutLocation(block), "out(loc)", opId); 503 } 504 end("IR"); 505 } 506 507 private void printLiveVars(int[] live, String lbl, int opId) { 508 out.printf("nr %4d ", opId).print(COLUMN_END).print(" instruction "); 509 out.print(lbl).print(" ["); 510 for (int i = 0; i < live.length; i++) { 511 if (i > 0) { 512 out.print(", "); 513 } 514 int varNum = live[i]; 515 Value value = varNum >= 0 ? livenessInfo.getVariable(varNum) : Value.ILLEGAL; 516 out.print(i).print(": ").print(value.toString()); 517 } 518 out.print(']'); 519 out.print(COLUMN_END); 520 out.println(COLUMN_END); 521 } 522 523 private void printLiveLoc(Value[] values, String lbl, int opId) { 524 if (values != null) { 525 out.printf("nr %4d ", opId).print(COLUMN_END).print(" instruction "); 526 out.print(lbl).print(" ["); 527 for (int i = 0; i < values.length; i++) { 528 if (i > 0) { 529 out.print(", "); 530 } 531 out.print(i).print(": ").print(values[i].toString()); 532 } 533 out.print(']'); 534 out.print(COLUMN_END); 535 out.println(COLUMN_END); 536 } 537 } 538 539 private void printLIRInstruction(LIRInstruction inst) { 540 if (inst == null) { 541 out.print("nr -1 ").print(COLUMN_END).print(" instruction ").print("<deleted>").print(COLUMN_END); 542 out.println(COLUMN_END); 543 } else { 544 out.printf("nr %4d ", inst.id()).print(COLUMN_END); 545 546 final StringBuilder stateString = new StringBuilder(); 547 inst.forEachState(state -> { 548 if (state.hasDebugInfo()) { 549 DebugInfo di = state.debugInfo(); 550 stateString.append(debugInfoToString(di.getBytecodePosition(), di.getReferenceMap(), state.getLiveBasePointers(), di.getCalleeSaveInfo())); 551 } else { 552 stateString.append(debugInfoToString(state.topFrame, null, state.getLiveBasePointers(), null)); 553 } 554 }); 555 if (stateString.length() > 0) { 556 int level = out.indentationLevel(); 557 out.adjustIndentation(-level); 558 out.print(" st ").print(HOVER_START).print("st").print(HOVER_SEP).print(stateString.toString()).print(HOVER_END).print(COLUMN_END); 559 out.adjustIndentation(level); 560 } 561 562 out.print(" instruction ").print(inst.toString(res)).print(COLUMN_END); 563 out.println(COLUMN_END); 564 } 565 } 566 567 private String nodeToString(Node node) { 568 if (node == null) { 569 return "-"; 570 } 571 String prefix; 572 if (node instanceof AbstractBeginNode && (lir == null && schedule == null)) { 573 prefix = "B"; 574 } else if (node instanceof ValueNode) { 575 ValueNode value = (ValueNode) node; 576 if (value.getStackKind() == JavaKind.Illegal) { 577 prefix = "v"; 578 } else { 579 prefix = String.valueOf(toLowerCase(value.getStackKind().getTypeChar())); 580 } 581 } else { 582 prefix = "?"; 583 } 584 return prefix + node.toString(Verbosity.Id); 585 } 586 587 private String blockToString(AbstractBlockBase<?> block) { 588 if (lir == null && schedule == null && block instanceof Block) { 589 // During all the front-end phases, the block schedule is built only for the debug 590 // output. 591 // Therefore, the block numbers would be different for every CFG printed -> use the id 592 // of the first instruction. 593 return "B" + ((Block) block).getBeginNode().toString(Verbosity.Id); 594 } else { 595 // LIR instructions contain references to blocks and these blocks are printed as the 596 // blockID -> use the blockID. 597 return "B" + block.getId(); 598 } 599 } 600 601 IntervalVisitor intervalVisitor = new IntervalVisitor() { 602 603 /** 604 * @return a formatted description of the operand that the C1Visualizer can handle. 605 */ 606 String getFormattedOperand(Value operand) { 607 String s = operand.toString(); 608 int last = s.lastIndexOf('|'); 609 if (last != -1) { 610 return s.substring(0, last) + "|" + operand.getPlatformKind().getTypeChar(); 611 } 612 return s; 613 } 614 615 @Override 616 public void visitIntervalStart(Value parentOperand, Value splitOperand, Value location, Value hint, String typeName) { 617 out.printf("%s %s ", getFormattedOperand(splitOperand), typeName); 618 if (location != null) { 619 out.printf("\"[%s]\"", getFormattedOperand(location)); 620 } else { 621 out.printf("\"[%s]\"", getFormattedOperand(splitOperand)); 622 } 623 out.printf(" %s %s ", getFormattedOperand(parentOperand), hint != null ? getFormattedOperand(hint) : -1); 624 } 625 626 @Override 627 public void visitRange(int from, int to) { 628 out.printf("[%d, %d[", from, to); 629 } 630 631 @Override 632 public void visitUsePos(int usePos, Object registerPriority) { 633 out.printf("%d %s ", usePos, registerPriority); 634 } 635 636 @Override 637 public void visitIntervalEnd(Object spillState) { 638 out.printf(" \"%s\"", spillState); 639 out.println(); 640 } 641 642 }; 643 644 public void printIntervals(String label, IntervalDumper intervals) { 645 begin("intervals"); 646 out.println(String.format("name \"%s\"", label)); 647 648 intervals.visitIntervals(intervalVisitor); 649 650 end("intervals"); 651 } 652 653 public void printSchedule(String message, ScheduleResult theSchedule) { 654 schedule = theSchedule; 655 cfg = schedule.getCFG(); 656 printedNodes = new NodeBitMap(cfg.graph); 657 658 begin("cfg"); 659 out.print("name \"").print(message).println('"'); 660 for (Block b : schedule.getCFG().getBlocks()) { 661 if (schedule.nodesFor(b) != null) { 662 printScheduledBlock(b, schedule.nodesFor(b)); 663 } 664 } 665 end("cfg"); 666 667 schedule = null; 668 cfg = null; 669 printedNodes = null; 670 } 671 672 private void printScheduledBlock(Block block, List<Node> nodesFor) { 673 printBlockProlog(block); 674 begin("IR"); 675 out.println("HIR"); 676 out.disableIndentation(); 677 678 if (block.getBeginNode() instanceof AbstractMergeNode) { 679 // Currently phi functions are not in the schedule, so print them separately here. 680 for (ValueNode phi : ((AbstractMergeNode) block.getBeginNode()).phis()) { 681 printNode(phi, false); 682 } 683 } 684 685 for (Node n : nodesFor) { 686 printNode(n, false); 687 } 688 689 out.enableIndentation(); 690 end("IR"); 691 692 printBlockEpilog(block); 693 } 694 695 public void printTraces(String label, TraceBuilderResult traces) { 696 begin("cfg"); 697 out.print("name \"").print(label).println('"'); 698 699 for (Trace trace : traces.getTraces()) { 700 printTrace(trace, traces); 701 } 702 703 end("cfg"); 704 } 705 706 private void printTrace(Trace trace, TraceBuilderResult traceBuilderResult) { 707 printTraceProlog(trace, traceBuilderResult); 708 printTraceInstructions(trace, traceBuilderResult); 709 printTraceEpilog(); 710 } 711 712 private void printTraceProlog(Trace trace, TraceBuilderResult traceBuilderResult) { 713 begin("block"); 714 715 out.print("name \"").print(traceToString(trace)).println('"'); 716 out.println("from_bci -1"); 717 out.println("to_bci -1"); 718 719 out.print("predecessors "); 720 for (Trace pred : getPredecessors(trace, traceBuilderResult)) { 721 out.print("\"").print(traceToString(pred)).print("\" "); 722 } 723 out.println(); 724 725 out.print("successors "); 726 for (Trace succ : getSuccessors(trace, traceBuilderResult)) { 727 // if (!succ.isExceptionEntry()) { 728 out.print("\"").print(traceToString(succ)).print("\" "); 729 // } 730 } 731 out.println(); 732 733 out.print("xhandlers"); 734 // TODO(je) add support for exception handler 735 out.println(); 736 737 out.print("flags "); 738 // TODO(je) add support for flags 739 out.println(); 740 // TODO(je) add support for loop infos 741 } 742 743 private void printTraceInstructions(Trace trace, TraceBuilderResult traceBuilderResult) { 744 if (lir == null) { 745 return; 746 } 747 begin("IR"); 748 out.println("LIR"); 749 750 for (AbstractBlockBase<?> block : trace.getBlocks()) { 751 ArrayList<LIRInstruction> lirInstructions = lir.getLIRforBlock(block); 752 if (lirInstructions == null) { 753 continue; 754 } 755 printBlockInstruction(block, traceBuilderResult); 756 for (int i = 0; i < lirInstructions.size(); i++) { 757 LIRInstruction inst = lirInstructions.get(i); 758 printLIRInstruction(inst); 759 } 760 } 761 end("IR"); 762 } 763 764 private void printBlockInstruction(AbstractBlockBase<?> block, TraceBuilderResult traceBuilderResult) { 765 out.print("nr ").print(block.toString()).print(COLUMN_END).print(" instruction "); 766 767 if (block.getPredecessorCount() > 0) { 768 out.print("<- "); 769 printBlockListWithTrace(Arrays.asList(block.getPredecessors()), traceBuilderResult); 770 out.print(" "); 771 } 772 if (block.getSuccessorCount() > 0) { 773 out.print("-> "); 774 printBlockListWithTrace(Arrays.asList(block.getSuccessors()), traceBuilderResult); 775 } 776 777 out.print(COLUMN_END); 778 out.println(COLUMN_END); 779 } 780 781 private void printBlockListWithTrace(List<? extends AbstractBlockBase<?>> blocks, TraceBuilderResult traceBuilderResult) { 782 Iterator<? extends AbstractBlockBase<?>> it = blocks.iterator(); 783 printBlockWithTrace(it.next(), traceBuilderResult); 784 while (it.hasNext()) { 785 out.print(","); 786 printBlockWithTrace(it.next(), traceBuilderResult); 787 } 788 } 789 790 private void printBlockWithTrace(AbstractBlockBase<?> block, TraceBuilderResult traceBuilderResult) { 791 out.print(block.toString()); 792 out.print("[T").print(traceBuilderResult.getTraceForBlock(block).getId()).print("]"); 793 } 794 795 private void printTraceEpilog() { 796 end("block"); 797 } 798 799 private static boolean isLoopBackEdge(AbstractBlockBase<?> src, AbstractBlockBase<?> dst) { 800 return dst.isLoopHeader() && dst.getLoop().equals(src.getLoop()); 801 } 802 803 private static List<Trace> getSuccessors(Trace trace, TraceBuilderResult traceBuilderResult) { 804 BitSet bs = new BitSet(traceBuilderResult.getTraces().size()); 805 for (AbstractBlockBase<?> block : trace.getBlocks()) { 806 for (AbstractBlockBase<?> s : block.getSuccessors()) { 807 Trace otherTrace = traceBuilderResult.getTraceForBlock(s); 808 int otherTraceId = otherTrace.getId(); 809 if (trace.getId() != otherTraceId || isLoopBackEdge(block, s)) { 810 bs.set(otherTraceId); 811 } 812 } 813 } 814 List<Trace> succ = new ArrayList<>(); 815 for (int i = bs.nextSetBit(0); i >= 0; i = bs.nextSetBit(i + 1)) { 816 succ.add(traceBuilderResult.getTraces().get(i)); 817 } 818 return succ; 819 } 820 821 private static List<Trace> getPredecessors(Trace trace, TraceBuilderResult traceBuilderResult) { 822 BitSet bs = new BitSet(traceBuilderResult.getTraces().size()); 823 for (AbstractBlockBase<?> block : trace.getBlocks()) { 824 for (AbstractBlockBase<?> p : block.getPredecessors()) { 825 Trace otherTrace = traceBuilderResult.getTraceForBlock(p); 826 int otherTraceId = otherTrace.getId(); 827 if (trace.getId() != otherTraceId || isLoopBackEdge(p, block)) { 828 bs.set(traceBuilderResult.getTraceForBlock(p).getId()); 829 } 830 } 831 } 832 List<Trace> pred = new ArrayList<>(); 833 for (int i = bs.nextSetBit(0); i >= 0; i = bs.nextSetBit(i + 1)) { 834 pred.add(traceBuilderResult.getTraces().get(i)); 835 } 836 return pred; 837 } 838 839 private static String traceToString(Trace trace) { 840 return new StringBuilder("T").append(trace.getId()).toString(); 841 } 842 843 }