summaryrefslogtreecommitdiff
path: root/compiler/optimizing/graph_visualizer.cc
diff options
context:
space:
mode:
authorChris Gross <chrisgross@google.com>2021-01-26 11:21:07 -0800
committerChris Gross <chrisgross@google.com>2021-01-26 11:21:07 -0800
commit2ca15e8c3e0f3e7356d7a6d9a87a61659342f867 (patch)
treee88119c8bebd70e06df7eeebe62e81760848d224 /compiler/optimizing/graph_visualizer.cc
parent7e5830d1ea13d23b6119a9c4856af3056f44ef92 (diff)
parent7c52f3136afed97406d9114f8e9a01dfafbb75ea (diff)
Merge SP1A.210122.003
Change-Id: I886d1cf8c0cf40d6300200667b66cf1dfa5d80ec
Diffstat (limited to 'compiler/optimizing/graph_visualizer.cc')
-rw-r--r--compiler/optimizing/graph_visualizer.cc197
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