aoqi@0: /* aoqi@0: * Copyright (c) 2005, 2014, Oracle and/or its affiliates. All rights reserved. aoqi@0: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. aoqi@0: * aoqi@0: * This code is free software; you can redistribute it and/or modify it aoqi@0: * under the terms of the GNU General Public License version 2 only, as aoqi@0: * published by the Free Software Foundation. aoqi@0: * aoqi@0: * This code is distributed in the hope that it will be useful, but WITHOUT aoqi@0: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or aoqi@0: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License aoqi@0: * version 2 for more details (a copy is included in the LICENSE file that aoqi@0: * accompanied this code). aoqi@0: * aoqi@0: * You should have received a copy of the GNU General Public License version aoqi@0: * 2 along with this work; if not, write to the Free Software Foundation, aoqi@0: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. aoqi@0: * aoqi@0: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA aoqi@0: * or visit www.oracle.com if you need additional information or have any aoqi@0: * questions. aoqi@0: * aoqi@0: */ aoqi@0: aoqi@0: #include "precompiled.hpp" aoqi@0: #include "c1/c1_CFGPrinter.hpp" aoqi@0: #include "c1/c1_IR.hpp" aoqi@0: #include "c1/c1_InstructionPrinter.hpp" aoqi@0: #include "c1/c1_LIR.hpp" aoqi@0: #include "c1/c1_LinearScan.hpp" aoqi@0: #include "c1/c1_ValueStack.hpp" aoqi@0: aoqi@0: #ifndef PRODUCT aoqi@0: aoqi@0: aoqi@0: class CFGPrinterOutput : public CHeapObj { aoqi@0: private: aoqi@0: outputStream* _output; aoqi@0: aoqi@0: Compilation* _compilation; aoqi@0: bool _do_print_HIR; aoqi@0: bool _do_print_LIR; aoqi@0: aoqi@0: class PrintBlockClosure: public BlockClosure { aoqi@0: void block_do(BlockBegin* block) { if (block != NULL) CFGPrinter::output()->print_block(block); } aoqi@0: }; aoqi@0: aoqi@0: aoqi@0: outputStream* output() { assert(_output != NULL, ""); return _output; } aoqi@0: aoqi@0: void inc_indent(); aoqi@0: void dec_indent(); aoqi@0: void print(const char* format, ...) ATTRIBUTE_PRINTF(2, 3); aoqi@0: void print_begin(const char* tag); aoqi@0: void print_end(const char* tag); aoqi@0: aoqi@0: char* method_name(ciMethod* method, bool short_name = false); aoqi@0: aoqi@0: public: aoqi@0: CFGPrinterOutput(); aoqi@0: aoqi@0: void set_compilation(Compilation* compilation) { _compilation = compilation; } aoqi@0: void set_print_flags(bool do_print_HIR, bool do_print_LIR) { _do_print_HIR = do_print_HIR; _do_print_LIR = do_print_LIR; } aoqi@0: aoqi@0: void print_compilation(); aoqi@0: void print_intervals(IntervalList* intervals, const char* name); aoqi@0: aoqi@0: void print_state(BlockBegin* block); aoqi@0: void print_operand(Value instr); aoqi@0: void print_HIR(Value instr); aoqi@0: void print_HIR(BlockBegin* block); aoqi@0: void print_LIR(BlockBegin* block); aoqi@0: void print_block(BlockBegin* block); aoqi@0: void print_cfg(BlockList* blocks, const char* name); aoqi@0: void print_cfg(IR* blocks, const char* name); aoqi@0: }; aoqi@0: aoqi@0: CFGPrinterOutput* CFGPrinter::_output = NULL; aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: void CFGPrinter::print_compilation(Compilation* compilation) { aoqi@0: if (_output == NULL) { aoqi@0: _output = new CFGPrinterOutput(); aoqi@0: } aoqi@0: output()->set_compilation(compilation); aoqi@0: output()->print_compilation(); aoqi@0: } aoqi@0: aoqi@0: void CFGPrinter::print_cfg(BlockList* blocks, const char* name, bool do_print_HIR, bool do_print_LIR) { aoqi@0: output()->set_print_flags(do_print_HIR, do_print_LIR); aoqi@0: output()->print_cfg(blocks, name); aoqi@0: } aoqi@0: aoqi@0: void CFGPrinter::print_cfg(IR* blocks, const char* name, bool do_print_HIR, bool do_print_LIR) { aoqi@0: output()->set_print_flags(do_print_HIR, do_print_LIR); aoqi@0: output()->print_cfg(blocks, name); aoqi@0: } aoqi@0: aoqi@0: aoqi@0: void CFGPrinter::print_intervals(IntervalList* intervals, const char* name) { aoqi@0: output()->print_intervals(intervals, name); aoqi@0: } aoqi@0: aoqi@0: aoqi@0: aoqi@0: CFGPrinterOutput::CFGPrinterOutput() aoqi@0: : _output(new(ResourceObj::C_HEAP, mtCompiler) fileStream("output.cfg")) aoqi@0: { aoqi@0: } aoqi@0: aoqi@0: aoqi@0: aoqi@0: void CFGPrinterOutput::inc_indent() { aoqi@0: output()->inc(); aoqi@0: output()->inc(); aoqi@0: } aoqi@0: aoqi@0: void CFGPrinterOutput::dec_indent() { aoqi@0: output()->dec(); aoqi@0: output()->dec(); aoqi@0: } aoqi@0: aoqi@0: void CFGPrinterOutput::print(const char* format, ...) { aoqi@0: output()->indent(); aoqi@0: aoqi@0: va_list ap; aoqi@0: va_start(ap, format); aoqi@0: output()->vprint_cr(format, ap); aoqi@0: va_end(ap); aoqi@0: } aoqi@0: aoqi@0: void CFGPrinterOutput::print_begin(const char* tag) { aoqi@0: output()->indent(); aoqi@0: output()->print_cr("begin_%s", tag); aoqi@0: inc_indent(); aoqi@0: } aoqi@0: aoqi@0: void CFGPrinterOutput::print_end(const char* tag) { aoqi@0: dec_indent(); aoqi@0: output()->indent(); aoqi@0: output()->print_cr("end_%s", tag); aoqi@0: } aoqi@0: aoqi@0: aoqi@0: char* CFGPrinterOutput::method_name(ciMethod* method, bool short_name) { aoqi@0: stringStream name; aoqi@0: if (short_name) { aoqi@0: method->print_short_name(&name); aoqi@0: } else { aoqi@0: method->print_name(&name); aoqi@0: } aoqi@0: return name.as_string(); aoqi@0: aoqi@0: } aoqi@0: aoqi@0: aoqi@0: void CFGPrinterOutput::print_compilation() { aoqi@0: print_begin("compilation"); aoqi@0: aoqi@0: print("name \"%s\"", method_name(_compilation->method(), true)); aoqi@0: print("method \"%s\"", method_name(_compilation->method())); aoqi@0: print("date "INT64_FORMAT, (int64_t) os::javaTimeMillis()); aoqi@0: aoqi@0: print_end("compilation"); aoqi@0: } aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: void CFGPrinterOutput::print_state(BlockBegin* block) { aoqi@0: print_begin("states"); aoqi@0: aoqi@0: InstructionPrinter ip(true, output()); aoqi@0: aoqi@0: ValueStack* state = block->state(); aoqi@0: int index; aoqi@0: Value value; aoqi@0: aoqi@0: for_each_state(state) { aoqi@0: print_begin("locals"); aoqi@0: print("size %d", state->locals_size()); aoqi@0: print("method \"%s\"", method_name(state->scope()->method())); aoqi@0: aoqi@0: for_each_local_value(state, index, value) { aoqi@0: ip.print_phi(index, value, block); aoqi@0: print_operand(value); aoqi@0: output()->cr(); aoqi@0: } aoqi@0: print_end("locals"); aoqi@0: aoqi@0: if (state->stack_size() > 0) { aoqi@0: print_begin("stack"); aoqi@0: print("size %d", state->stack_size()); aoqi@0: print("method \"%s\"", method_name(state->scope()->method())); aoqi@0: aoqi@0: for_each_stack_value(state, index, value) { aoqi@0: ip.print_phi(index, value, block); aoqi@0: print_operand(value); aoqi@0: output()->cr(); aoqi@0: } aoqi@0: aoqi@0: print_end("stack"); aoqi@0: } aoqi@0: aoqi@0: if (state->locks_size() > 0) { aoqi@0: print_begin("locks"); aoqi@0: print("size %d", state->locks_size()); aoqi@0: print("method \"%s\"", method_name(state->scope()->method())); aoqi@0: aoqi@0: for_each_lock_value(state, index, value) { aoqi@0: ip.print_phi(index, value, block); aoqi@0: print_operand(value); aoqi@0: output()->cr(); aoqi@0: } aoqi@0: print_end("locks"); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: print_end("states"); aoqi@0: } aoqi@0: aoqi@0: aoqi@0: void CFGPrinterOutput::print_operand(Value instr) { aoqi@0: if (instr->operand()->is_virtual()) { aoqi@0: output()->print(" \""); aoqi@0: instr->operand()->print(output()); aoqi@0: output()->print("\" "); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: void CFGPrinterOutput::print_HIR(Value instr) { aoqi@0: InstructionPrinter ip(true, output()); aoqi@0: aoqi@0: if (instr->is_pinned()) { aoqi@0: output()->put('.'); aoqi@0: } aoqi@0: aoqi@0: output()->print("%d %d ", instr->printable_bci(), instr->use_count()); aoqi@0: aoqi@0: print_operand(instr); aoqi@0: aoqi@0: ip.print_temp(instr); aoqi@0: output()->print(" "); aoqi@0: ip.print_instr(instr); aoqi@0: aoqi@0: output()->print_cr(" <|@"); aoqi@0: } aoqi@0: aoqi@0: void CFGPrinterOutput::print_HIR(BlockBegin* block) { aoqi@0: print_begin("HIR"); aoqi@0: aoqi@0: Value cur = block->next(); aoqi@0: while (cur != NULL) { aoqi@0: print_HIR(cur); aoqi@0: cur = cur->next(); aoqi@0: } aoqi@0: aoqi@0: print_end("HIR"); aoqi@0: } aoqi@0: aoqi@0: void CFGPrinterOutput::print_LIR(BlockBegin* block) { aoqi@0: print_begin("LIR"); aoqi@0: aoqi@0: for (int i = 0; i < block->lir()->length(); i++) { aoqi@0: block->lir()->at(i)->print_on(output()); aoqi@0: output()->print_cr(" <|@ "); aoqi@0: } aoqi@0: aoqi@0: print_end("LIR"); aoqi@0: } aoqi@0: aoqi@0: aoqi@0: void CFGPrinterOutput::print_block(BlockBegin* block) { aoqi@0: print_begin("block"); aoqi@0: aoqi@0: print("name \"B%d\"", block->block_id()); aoqi@0: aoqi@0: print("from_bci %d", block->bci()); aoqi@0: print("to_bci %d", (block->end() == NULL ? -1 : block->end()->printable_bci())); aoqi@0: aoqi@0: output()->indent(); aoqi@0: output()->print("predecessors "); aoqi@0: int i; aoqi@0: for (i = 0; i < block->number_of_preds(); i++) { aoqi@0: output()->print("\"B%d\" ", block->pred_at(i)->block_id()); aoqi@0: } aoqi@0: output()->cr(); aoqi@0: aoqi@0: output()->indent(); aoqi@0: output()->print("successors "); aoqi@0: for (i = 0; i < block->number_of_sux(); i++) { aoqi@0: output()->print("\"B%d\" ", block->sux_at(i)->block_id()); aoqi@0: } aoqi@0: output()->cr(); aoqi@0: aoqi@0: output()->indent(); aoqi@0: output()->print("xhandlers"); aoqi@0: for (i = 0; i < block->number_of_exception_handlers(); i++) { aoqi@0: output()->print("\"B%d\" ", block->exception_handler_at(i)->block_id()); aoqi@0: } aoqi@0: output()->cr(); aoqi@0: aoqi@0: output()->indent(); aoqi@0: output()->print("flags "); aoqi@0: if (block->is_set(BlockBegin::std_entry_flag)) output()->print("\"std\" "); aoqi@0: if (block->is_set(BlockBegin::osr_entry_flag)) output()->print("\"osr\" "); aoqi@0: if (block->is_set(BlockBegin::exception_entry_flag)) output()->print("\"ex\" "); aoqi@0: if (block->is_set(BlockBegin::subroutine_entry_flag)) output()->print("\"sr\" "); aoqi@0: if (block->is_set(BlockBegin::backward_branch_target_flag)) output()->print("\"bb\" "); aoqi@0: if (block->is_set(BlockBegin::parser_loop_header_flag)) output()->print("\"plh\" "); aoqi@0: if (block->is_set(BlockBegin::critical_edge_split_flag)) output()->print("\"ces\" "); aoqi@0: if (block->is_set(BlockBegin::linear_scan_loop_header_flag)) output()->print("\"llh\" "); aoqi@0: if (block->is_set(BlockBegin::linear_scan_loop_end_flag)) output()->print("\"lle\" "); aoqi@0: output()->cr(); aoqi@0: aoqi@0: if (block->dominator() != NULL) { aoqi@0: print("dominator \"B%d\"", block->dominator()->block_id()); aoqi@0: } aoqi@0: if (block->loop_index() != -1) { aoqi@0: print("loop_index %d", block->loop_index()); aoqi@0: print("loop_depth %d", block->loop_depth()); aoqi@0: } aoqi@0: aoqi@0: if (block->first_lir_instruction_id() != -1) { aoqi@0: print("first_lir_id %d", block->first_lir_instruction_id()); aoqi@0: print("last_lir_id %d", block->last_lir_instruction_id()); aoqi@0: } aoqi@0: aoqi@0: if (_do_print_HIR) { aoqi@0: print_state(block); aoqi@0: print_HIR(block); aoqi@0: } aoqi@0: aoqi@0: if (_do_print_LIR) { aoqi@0: print_LIR(block); aoqi@0: } aoqi@0: aoqi@0: print_end("block"); aoqi@0: } aoqi@0: aoqi@0: aoqi@0: aoqi@0: void CFGPrinterOutput::print_cfg(BlockList* blocks, const char* name) { aoqi@0: print_begin("cfg"); aoqi@0: print("name \"%s\"", name); aoqi@0: aoqi@0: PrintBlockClosure print_block; aoqi@0: blocks->iterate_forward(&print_block); aoqi@0: aoqi@0: print_end("cfg"); aoqi@0: output()->flush(); aoqi@0: } aoqi@0: aoqi@0: void CFGPrinterOutput::print_cfg(IR* blocks, const char* name) { aoqi@0: print_begin("cfg"); aoqi@0: print("name \"%s\"", name); aoqi@0: aoqi@0: PrintBlockClosure print_block; aoqi@0: blocks->iterate_preorder(&print_block); aoqi@0: aoqi@0: print_end("cfg"); aoqi@0: output()->flush(); aoqi@0: } aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: void CFGPrinterOutput::print_intervals(IntervalList* intervals, const char* name) { aoqi@0: print_begin("intervals"); aoqi@0: print("name \"%s\"", name); aoqi@0: aoqi@0: for (int i = 0; i < intervals->length(); i++) { aoqi@0: if (intervals->at(i) != NULL) { aoqi@0: intervals->at(i)->print(output()); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: print_end("intervals"); aoqi@0: output()->flush(); aoqi@0: } aoqi@0: aoqi@0: aoqi@0: #endif