From dc281e776c0395b54200c62626f90417f092a2bf Mon Sep 17 00:00:00 2001 From: Alex Light Date: Wed, 6 Jan 2021 12:35:31 -0800 Subject: Add operator<< for HGraph and HInstructions. Include helpers for printing arguments as well. Test: ./test.py --host Change-Id: I692fd5bd32a8a39da0defd9454d56ccf2480f229 --- compiler/optimizing/graph_visualizer.cc | 147 ++++++++++++++++++++++---------- 1 file changed, 101 insertions(+), 46 deletions(-) (limited to 'compiler/optimizing/graph_visualizer.cc') diff --git a/compiler/optimizing/graph_visualizer.cc b/compiler/optimizing/graph_visualizer.cc index 44a64c1d51..da34af28a5 100644 --- a/compiler/optimizing/graph_visualizer.cc +++ b/compiler/optimizing/graph_visualizer.cc @@ -44,6 +44,10 @@ namespace art { +// Unique pass-name to identify that the dump is for printing to log. +constexpr const char* kDebugDumpName = "debug"; +constexpr const char* kDebugDumpGraphName = "debug_graph"; + using android::base::StringPrintf; static bool HasWhitespace(const char* str) { @@ -196,6 +200,7 @@ class HGraphVisualizerPrinter : public HGraphDelegateVisitor { bool is_after_pass, bool graph_in_bad_state, const CodeGenerator* codegen, + const BlockNamer& namer, const DisassemblyInformation* disasm_info = nullptr) : HGraphDelegateVisitor(graph), output_(output), @@ -204,6 +209,7 @@ class HGraphVisualizerPrinter : public HGraphDelegateVisitor { graph_in_bad_state_(graph_in_bad_state), codegen_(codegen), disasm_info_(disasm_info), + namer_(namer), disassembler_(disasm_info_ != nullptr ? new HGraphVisualizerDisassembler( codegen_->GetInstructionSet(), @@ -231,6 +237,11 @@ class HGraphVisualizerPrinter : public HGraphDelegateVisitor { output_ << "end_" << name << "\n"; } + void PrintProperty(const char* name, HBasicBlock* blk) { + AddIndent(); + output_ << name << " \"" << namer_.GetName(blk) << "\"\n"; + } + void PrintProperty(const char* name, const char* property) { AddIndent(); output_ << name << " \"" << property << "\"\n"; @@ -266,7 +277,7 @@ class HGraphVisualizerPrinter : public HGraphDelegateVisitor { AddIndent(); output_ << "predecessors"; for (HBasicBlock* predecessor : block->GetPredecessors()) { - output_ << " \"B" << predecessor->GetBlockId() << "\" "; + output_ << " \"" << namer_.GetName(predecessor) << "\" "; } if (block->IsEntryBlock() && (disasm_info_ != nullptr)) { output_ << " \"" << kDisassemblyBlockFrameEntry << "\" "; @@ -278,20 +289,24 @@ class HGraphVisualizerPrinter : public HGraphDelegateVisitor { AddIndent(); output_ << "successors"; for (HBasicBlock* successor : block->GetNormalSuccessors()) { - output_ << " \"B" << successor->GetBlockId() << "\" "; + output_ << " \"" << namer_.GetName(successor) << "\" "; } output_<< "\n"; } void PrintExceptionHandlers(HBasicBlock* block) { + bool has_slow_paths = block->IsExitBlock() && + (disasm_info_ != nullptr) && + !disasm_info_->GetSlowPathIntervals().empty(); + if (IsDebugDump() && block->GetExceptionalSuccessors().empty() && !has_slow_paths) { + return; + } AddIndent(); output_ << "xhandlers"; for (HBasicBlock* handler : block->GetExceptionalSuccessors()) { - output_ << " \"B" << handler->GetBlockId() << "\" "; + output_ << " \"" << namer_.GetName(handler) << "\" "; } - if (block->IsExitBlock() && - (disasm_info_ != nullptr) && - !disasm_info_->GetSlowPathIntervals().empty()) { + if (has_slow_paths) { output_ << " \"" << kDisassemblyBlockSlowPaths << "\" "; } output_<< "\n"; @@ -393,11 +408,10 @@ class HGraphVisualizerPrinter : public HGraphDelegateVisitor { void VisitLoadClass(HLoadClass* load_class) override { StartAttributeStream("load_kind") << load_class->GetLoadKind(); - const char* descriptor = load_class->GetDexFile().GetTypeDescriptor( - load_class->GetDexFile().GetTypeId(load_class->GetTypeIndex())); - StartAttributeStream("class_name") << PrettyDescriptor(descriptor); - StartAttributeStream("gen_clinit_check") << std::boolalpha - << load_class->MustGenerateClinitCheck() << std::noboolalpha; + StartAttributeStream("class_name") + << load_class->GetDexFile().PrettyType(load_class->GetTypeIndex()); + StartAttributeStream("gen_clinit_check") + << std::boolalpha << load_class->MustGenerateClinitCheck() << std::noboolalpha; StartAttributeStream("needs_access_check") << std::boolalpha << load_class->NeedsAccessCheck() << std::noboolalpha; } @@ -410,8 +424,13 @@ class HGraphVisualizerPrinter : public HGraphDelegateVisitor { void VisitLoadMethodType(HLoadMethodType* load_method_type) override { StartAttributeStream("load_kind") << "RuntimeCall"; const DexFile& dex_file = load_method_type->GetDexFile(); - const dex::ProtoId& proto_id = dex_file.GetProtoId(load_method_type->GetProtoIndex()); - StartAttributeStream("method_type") << dex_file.GetProtoSignature(proto_id); + if (dex_file.NumProtoIds() >= load_method_type->GetProtoIndex().index_) { + const dex::ProtoId& proto_id = dex_file.GetProtoId(load_method_type->GetProtoIndex()); + StartAttributeStream("method_type") << dex_file.GetProtoSignature(proto_id); + } else { + StartAttributeStream("method_type") + << "<GetProtoIndex() << ">>"; + } } void VisitLoadString(HLoadString* load_string) override { @@ -609,6 +628,10 @@ class HGraphVisualizerPrinter : public HGraphDelegateVisitor { return strcmp(pass_name_, name) == 0; } + bool IsDebugDump() { + return IsPass(kDebugDumpGraphName) || IsPass(kDebugDumpName); + } + void PrintInstruction(HInstruction* instruction) { output_ << instruction->DebugName(); HConstInputsRef inputs = instruction->GetInputs(); @@ -624,6 +647,10 @@ class HGraphVisualizerPrinter : public HGraphDelegateVisitor { } else { StartAttributeStream("dex_pc") << "n/a"; } + if (IsPass(kDebugDumpName)) { + // Include block name for logcat use. + StartAttributeStream("block") << namer_.GetName(instruction->GetBlock()); + } instruction->Accept(this); if (instruction->HasEnvironment()) { StringList envs; @@ -678,10 +705,10 @@ class HGraphVisualizerPrinter : public HGraphDelegateVisitor { if (loop_info == nullptr) { StartAttributeStream("loop") << "none"; } else { - StartAttributeStream("loop") << "B" << loop_info->GetHeader()->GetBlockId(); + StartAttributeStream("loop") << namer_.GetName(loop_info->GetHeader()); HLoopInformation* outer = loop_info->GetPreHeader()->GetLoopInformation(); if (outer != nullptr) { - StartAttributeStream("outer_loop") << "B" << outer->GetHeader()->GetBlockId(); + StartAttributeStream("outer_loop") << namer_.GetName(outer->GetHeader()); } else { StartAttributeStream("outer_loop") << "none"; } @@ -692,7 +719,8 @@ class HGraphVisualizerPrinter : public HGraphDelegateVisitor { // For the builder and the inliner, we want to add extra information on HInstructions // that have reference types, and also HInstanceOf/HCheckcast. if ((IsPass(HGraphBuilder::kBuilderPassName) - || IsPass(HInliner::kInlinerPassName)) + || IsPass(HInliner::kInlinerPassName) + || IsDebugDump()) && (instruction->GetType() == DataType::Type::kReference || instruction->IsInstanceOf() || instruction->IsCheckCast())) { @@ -722,6 +750,7 @@ class HGraphVisualizerPrinter : public HGraphDelegateVisitor { // doesn't run or doesn't inline anything, the NullConstant remains untyped. // So we should check NullConstants for validity only after reference type propagation. DCHECK(graph_in_bad_state_ || + IsDebugDump() || (!is_after_pass_ && IsPass(HGraphBuilder::kBuilderPassName))) << instruction->DebugName() << instruction->GetId() << " has invalid rti " << (is_after_pass_ ? "after" : "before") << " pass " << pass_name_; @@ -821,12 +850,13 @@ class HGraphVisualizerPrinter : public HGraphDelegateVisitor { void Run() { StartTag("cfg"); - std::string pass_desc = std::string(pass_name_) - + " (" - + (is_after_pass_ ? "after" : "before") - + (graph_in_bad_state_ ? ", bad_state" : "") - + ")"; - PrintProperty("name", pass_desc.c_str()); + std::ostringstream oss; + oss << pass_name_; + if (!IsDebugDump()) { + oss << " (" << (is_after_pass_ ? "after" : "before") + << (graph_in_bad_state_ ? ", bad_state" : "") << ")"; + } + PrintProperty("name", oss.str().c_str()); if (disasm_info_ != nullptr) { DumpDisassemblyBlockForFrameEntry(); } @@ -846,12 +876,13 @@ class HGraphVisualizerPrinter : public HGraphDelegateVisitor { void VisitBasicBlock(HBasicBlock* block) override { StartTag("block"); - PrintProperty("name", "B", block->GetBlockId()); + PrintProperty("name", block); if (block->GetLifetimeStart() != kNoLifetime) { // Piggy back on these fields to show the lifetime of the block. PrintInt("from_bci", block->GetLifetimeStart()); PrintInt("to_bci", block->GetLifetimeEnd()); - } else { + } else if (!IsDebugDump()) { + // Don't print useless information to logcat. PrintInt("from_bci", -1); PrintInt("to_bci", -1); } @@ -861,30 +892,33 @@ class HGraphVisualizerPrinter : public HGraphDelegateVisitor { if (block->IsCatchBlock()) { PrintProperty("flags", "catch_block"); - } else { + } else if (!IsDebugDump()) { + // Don't print useless information to logcat PrintEmptyProperty("flags"); } if (block->GetDominator() != nullptr) { - PrintProperty("dominator", "B", block->GetDominator()->GetBlockId()); + PrintProperty("dominator", block->GetDominator()); } - StartTag("states"); - StartTag("locals"); - PrintInt("size", 0); - PrintProperty("method", "None"); - for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) { - AddIndent(); - HInstruction* instruction = it.Current(); - output_ << instruction->GetId() << " " << DataType::TypeId(instruction->GetType()) - << instruction->GetId() << "[ "; - for (const HInstruction* input : instruction->GetInputs()) { - output_ << input->GetId() << " "; + if (!IsDebugDump() || !block->GetPhis().IsEmpty()) { + StartTag("states"); + StartTag("locals"); + PrintInt("size", 0); + PrintProperty("method", "None"); + for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) { + AddIndent(); + HInstruction* instruction = it.Current(); + output_ << instruction->GetId() << " " << DataType::TypeId(instruction->GetType()) + << instruction->GetId() << "[ "; + for (const HInstruction* input : instruction->GetInputs()) { + output_ << input->GetId() << " "; + } + output_ << "]\n"; } - output_ << "]\n"; + EndTag("locals"); + EndTag("states"); } - EndTag("locals"); - EndTag("states"); StartTag("HIR"); PrintInstructions(block->GetPhis()); @@ -904,20 +938,31 @@ class HGraphVisualizerPrinter : public HGraphDelegateVisitor { const bool graph_in_bad_state_; const CodeGenerator* codegen_; const DisassemblyInformation* disasm_info_; + const BlockNamer& namer_; std::unique_ptr disassembler_; size_t indent_; DISALLOW_COPY_AND_ASSIGN(HGraphVisualizerPrinter); }; +std::ostream& HGraphVisualizer::OptionalDefaultNamer::PrintName(std::ostream& os, + HBasicBlock* blk) const { + if (namer_) { + return namer_->get().PrintName(os, blk); + } else { + return BlockNamer::PrintName(os, blk); + } +} + HGraphVisualizer::HGraphVisualizer(std::ostream* output, HGraph* graph, - const CodeGenerator* codegen) - : output_(output), graph_(graph), codegen_(codegen) {} + const CodeGenerator* codegen, + std::optional> namer) + : output_(output), graph_(graph), codegen_(codegen), namer_(namer) {} void HGraphVisualizer::PrintHeader(const char* method_name) const { DCHECK(output_ != nullptr); - HGraphVisualizerPrinter printer(graph_, *output_, "", true, false, codegen_); + HGraphVisualizerPrinter printer(graph_, *output_, "", true, false, codegen_, namer_); printer.StartTag("compilation"); printer.PrintProperty("name", method_name); printer.PrintProperty("method", method_name); @@ -939,6 +984,12 @@ std::string HGraphVisualizer::InsertMetaDataAsCompilationBlock(const std::string time_str.c_str()); } +void HGraphVisualizer::DumpGraphDebug() const { + DumpGraph(/* pass_name= */ kDebugDumpGraphName, + /* is_after_pass= */ false, + /* graph_in_bad_state= */ true); +} + void HGraphVisualizer::DumpGraph(const char* pass_name, bool is_after_pass, bool graph_in_bad_state) const { @@ -949,7 +1000,8 @@ void HGraphVisualizer::DumpGraph(const char* pass_name, pass_name, is_after_pass, graph_in_bad_state, - codegen_); + codegen_, + namer_); printer.Run(); } } @@ -963,6 +1015,7 @@ void HGraphVisualizer::DumpGraphWithDisassembly() const { /* is_after_pass= */ true, /* graph_in_bad_state= */ false, codegen_, + namer_, codegen_->GetDisassemblyInformation()); printer.Run(); } @@ -971,12 +1024,14 @@ void HGraphVisualizer::DumpGraphWithDisassembly() const { void HGraphVisualizer::DumpInstruction(std::ostream* output, HGraph* graph, HInstruction* instruction) { + BlockNamer namer; HGraphVisualizerPrinter printer(graph, *output, - /* pass_name= */ "debug", + /* pass_name= */ kDebugDumpName, /* is_after_pass= */ false, /* graph_in_bad_state= */ false, - /* codegen= */ nullptr); + /* codegen= */ nullptr, + /* namer= */ namer); printer.Run(instruction); } -- cgit v1.2.3