From c9fcfd02a69170cedcd4cf2e66826f246dff6267 Mon Sep 17 00:00:00 2001 From: Vladimir Marko Date: Tue, 5 Jan 2021 16:57:30 +0000 Subject: Optimizing: Add debugging output for HInstruction. Allow printing individual instruction and its arguments with the HGraphVisualizer. Arguments are dumped "recursively" (but implemented with a queue instead of actual recursion). For example, printing the Return instruction from the method Main.testLoop17 in 530-checker-lse yields v28 Return [i27] dex_pc:23 loop:none i27 Add [i24,i26] dex_pc:22 loop:none i24 Phi [i5,i15] dex_pc:n/a reg:0 is_catch_phi:false loop:none i5 IntConstant dex_pc:0 1 loop:none i15 IntConstant dex_pc:5 2 loop:none i26 InstanceFieldGet [l6] dex_pc:20 field_name:TestClass.i field_type:Int32 loop:none l6 NullCheck [l1] dex_pc:1 env:[[i5,_,_,l1,i2]] loop:none l1 ParameterValue dex_pc:n/a loop:none Test: Manual; modify LSE to print the instruction above. Change-Id: Iaf41ba62cd6a5a36236ad0abca082ebffcf6a20e --- compiler/optimizing/graph_visualizer.cc | 47 +++++++++++++++++++++++---------- 1 file changed, 33 insertions(+), 14 deletions(-) (limited to 'compiler/optimizing/graph_visualizer.cc') diff --git a/compiler/optimizing/graph_visualizer.cc b/compiler/optimizing/graph_visualizer.cc index f9c63c4486..44a64c1d51 100644 --- a/compiler/optimizing/graph_visualizer.cc +++ b/compiler/optimizing/graph_visualizer.cc @@ -195,7 +195,7 @@ class HGraphVisualizerPrinter : public HGraphDelegateVisitor { const char* pass_name, bool is_after_pass, bool graph_in_bad_state, - const CodeGenerator& codegen, + const CodeGenerator* codegen, const DisassemblyInformation* disasm_info = nullptr) : HGraphDelegateVisitor(graph), output_(output), @@ -206,10 +206,10 @@ class HGraphVisualizerPrinter : public HGraphDelegateVisitor { disasm_info_(disasm_info), 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) {} @@ -298,10 +298,11 @@ class HGraphVisualizerPrinter : public HGraphDelegateVisitor { } 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 +322,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()) { @@ -837,6 +838,12 @@ 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()); @@ -895,7 +902,7 @@ 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_; std::unique_ptr disassembler_; size_t indent_; @@ -905,7 +912,7 @@ class HGraphVisualizerPrinter : public HGraphDelegateVisitor { HGraphVisualizer::HGraphVisualizer(std::ostream* output, HGraph* graph, - const CodeGenerator& codegen) + const CodeGenerator* codegen) : output_(output), graph_(graph), codegen_(codegen) {} void HGraphVisualizer::PrintHeader(const char* method_name) const { @@ -956,9 +963,21 @@ void HGraphVisualizer::DumpGraphWithDisassembly() const { /* is_after_pass= */ true, /* graph_in_bad_state= */ false, codegen_, - codegen_.GetDisassemblyInformation()); + codegen_->GetDisassemblyInformation()); printer.Run(); } } +void HGraphVisualizer::DumpInstruction(std::ostream* output, + HGraph* graph, + HInstruction* instruction) { + HGraphVisualizerPrinter printer(graph, + *output, + /* pass_name= */ "debug", + /* is_after_pass= */ false, + /* graph_in_bad_state= */ false, + /* codegen= */ nullptr); + printer.Run(instruction); +} + } // namespace art -- cgit v1.2.3 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 From b8686ce4c93eba7192ed7ef89e7ffd9f3aa6cd07 Mon Sep 17 00:00:00 2001 From: Alex Light Date: Mon, 2 Nov 2020 08:48:33 -0800 Subject: Partial Load Store Elimination Add partial load-store elimination to the LSE pass. Partial LSE will move object allocations which only escape along certain execution paths closer to the escape point and allow more values to be eliminated. It does this by creating new predicated load and store instructions that are used when an object has only escaped some of the time. In cases where the object has not escaped a default value will be used. Test: ./test.py --host Test: ./test.py --target Bug: 67037140 Change-Id: Idde67eb59ec90de79747cde17b552eec05b58497 --- compiler/optimizing/graph_visualizer.cc | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'compiler/optimizing/graph_visualizer.cc') diff --git a/compiler/optimizing/graph_visualizer.cc b/compiler/optimizing/graph_visualizer.cc index da34af28a5..5a264b7a70 100644 --- a/compiler/optimizing/graph_visualizer.cc +++ b/compiler/optimizing/graph_visualizer.cc @@ -19,6 +19,7 @@ #include #include +#include #include #include "android-base/stringprintf.h" @@ -529,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(), @@ -541,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 { -- cgit v1.2.3