summaryrefslogtreecommitdiff
path: root/compiler/optimizing/graph_visualizer.cc
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/optimizing/graph_visualizer.cc')
-rw-r--r--compiler/optimizing/graph_visualizer.cc147
1 files changed, 101 insertions, 46 deletions
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")
+ << "<<Unknown proto-idx: " << load_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<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);
@@ -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);
}