diff options
author | Chris Gross <chrisgross@google.com> | 2021-01-26 11:21:07 -0800 |
---|---|---|
committer | Chris Gross <chrisgross@google.com> | 2021-01-26 11:21:07 -0800 |
commit | 2ca15e8c3e0f3e7356d7a6d9a87a61659342f867 (patch) | |
tree | e88119c8bebd70e06df7eeebe62e81760848d224 /compiler/optimizing/graph_visualizer.cc | |
parent | 7e5830d1ea13d23b6119a9c4856af3056f44ef92 (diff) | |
parent | 7c52f3136afed97406d9114f8e9a01dfafbb75ea (diff) |
Merge SP1A.210122.003
Change-Id: I886d1cf8c0cf40d6300200667b66cf1dfa5d80ec
Diffstat (limited to 'compiler/optimizing/graph_visualizer.cc')
-rw-r--r-- | compiler/optimizing/graph_visualizer.cc | 197 |
1 files changed, 140 insertions, 57 deletions
diff --git a/compiler/optimizing/graph_visualizer.cc b/compiler/optimizing/graph_visualizer.cc index f9c63c4486..5a264b7a70 100644 --- a/compiler/optimizing/graph_visualizer.cc +++ b/compiler/optimizing/graph_visualizer.cc @@ -19,6 +19,7 @@ #include <dlfcn.h> #include <cctype> +#include <ios> #include <sstream> #include "android-base/stringprintf.h" @@ -44,6 +45,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) { @@ -195,7 +200,8 @@ class HGraphVisualizerPrinter : public HGraphDelegateVisitor { const char* pass_name, bool is_after_pass, bool graph_in_bad_state, - const CodeGenerator& codegen, + const CodeGenerator* codegen, + const BlockNamer& namer, const DisassemblyInformation* disasm_info = nullptr) : HGraphDelegateVisitor(graph), output_(output), @@ -204,12 +210,13 @@ 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(), - codegen_.GetAssembler().CodeBufferBaseAddress(), - codegen_.GetAssembler().CodeBufferBaseAddress() - + codegen_.GetAssembler().CodeSize()) + codegen_->GetInstructionSet(), + codegen_->GetAssembler().CodeBufferBaseAddress(), + codegen_->GetAssembler().CodeBufferBaseAddress() + + codegen_->GetAssembler().CodeSize()) : nullptr), indent_(0) {} @@ -231,6 +238,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 +278,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,30 +290,35 @@ 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"; } void DumpLocation(std::ostream& stream, const Location& location) { + DCHECK(codegen_ != nullptr); if (location.IsRegister()) { - codegen_.DumpCoreRegister(stream, location.reg()); + codegen_->DumpCoreRegister(stream, location.reg()); } else if (location.IsFpuRegister()) { - codegen_.DumpFloatingPointRegister(stream, location.reg()); + codegen_->DumpFloatingPointRegister(stream, location.reg()); } else if (location.IsConstant()) { stream << "#"; HConstant* constant = location.GetConstant(); @@ -321,13 +338,13 @@ class HGraphVisualizerPrinter : public HGraphDelegateVisitor { } else if (location.IsStackSlot()) { stream << location.GetStackIndex() << "(sp)"; } else if (location.IsFpuRegisterPair()) { - codegen_.DumpFloatingPointRegister(stream, location.low()); + codegen_->DumpFloatingPointRegister(stream, location.low()); stream << "|"; - codegen_.DumpFloatingPointRegister(stream, location.high()); + codegen_->DumpFloatingPointRegister(stream, location.high()); } else if (location.IsRegisterPair()) { - codegen_.DumpCoreRegister(stream, location.low()); + codegen_->DumpCoreRegister(stream, location.low()); stream << "|"; - codegen_.DumpCoreRegister(stream, location.high()); + codegen_->DumpCoreRegister(stream, location.high()); } else if (location.IsUnallocated()) { stream << "unallocated"; } else if (location.IsDoubleStackSlot()) { @@ -392,11 +409,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; } @@ -409,8 +425,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") + << "<<Unknown proto-idx: " << load_method_type->GetProtoIndex() << ">>"; + } } void VisitLoadString(HLoadString* load_string) override { @@ -509,6 +530,13 @@ class HGraphVisualizerPrinter : public HGraphDelegateVisitor { StartAttributeStream("invoke_type") << "InvokePolymorphic"; } + void VisitPredicatedInstanceFieldGet(HPredicatedInstanceFieldGet* iget) override { + StartAttributeStream("field_name") << + iget->GetFieldInfo().GetDexFile().PrettyField(iget->GetFieldInfo().GetFieldIndex(), + /* with type */ false); + StartAttributeStream("field_type") << iget->GetFieldType(); + } + void VisitInstanceFieldGet(HInstanceFieldGet* iget) override { StartAttributeStream("field_name") << iget->GetFieldInfo().GetDexFile().PrettyField(iget->GetFieldInfo().GetFieldIndex(), @@ -521,6 +549,7 @@ class HGraphVisualizerPrinter : public HGraphDelegateVisitor { iset->GetFieldInfo().GetDexFile().PrettyField(iset->GetFieldInfo().GetFieldIndex(), /* with type */ false); StartAttributeStream("field_type") << iset->GetFieldType(); + StartAttributeStream("predicated") << std::boolalpha << iset->GetIsPredicatedSet(); } void VisitStaticFieldGet(HStaticFieldGet* sget) override { @@ -608,6 +637,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(); @@ -623,6 +656,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; @@ -677,10 +714,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"; } @@ -691,7 +728,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())) { @@ -721,6 +759,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_; @@ -820,12 +859,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(); } @@ -837,14 +877,21 @@ class HGraphVisualizerPrinter : public HGraphDelegateVisitor { Flush(); } + void Run(HInstruction* instruction) { + output_ << DataType::TypeId(instruction->GetType()) << instruction->GetId() << " "; + PrintInstruction(instruction); + Flush(); + } + 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); } @@ -854,30 +901,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()); @@ -895,22 +945,33 @@ class HGraphVisualizerPrinter : public HGraphDelegateVisitor { const char* pass_name_; const bool is_after_pass_; const bool graph_in_bad_state_; - const CodeGenerator& codegen_; + const CodeGenerator* codegen_; const DisassemblyInformation* disasm_info_; + const BlockNamer& namer_; std::unique_ptr<HGraphVisualizerDisassembler> 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<std::reference_wrapper<const BlockNamer>> 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); @@ -932,6 +993,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 { @@ -942,7 +1009,8 @@ void HGraphVisualizer::DumpGraph(const char* pass_name, pass_name, is_after_pass, graph_in_bad_state, - codegen_); + codegen_, + namer_); printer.Run(); } } @@ -956,9 +1024,24 @@ void HGraphVisualizer::DumpGraphWithDisassembly() const { /* is_after_pass= */ true, /* graph_in_bad_state= */ false, codegen_, - codegen_.GetDisassemblyInformation()); + namer_, + codegen_->GetDisassemblyInformation()); printer.Run(); } } +void HGraphVisualizer::DumpInstruction(std::ostream* output, + HGraph* graph, + HInstruction* instruction) { + BlockNamer namer; + HGraphVisualizerPrinter printer(graph, + *output, + /* pass_name= */ kDebugDumpName, + /* is_after_pass= */ false, + /* graph_in_bad_state= */ false, + /* codegen= */ nullptr, + /* namer= */ namer); + printer.Run(instruction); +} + } // namespace art |