diff options
author | 2021-01-05 16:57:30 +0000 | |
---|---|---|
committer | 2021-01-06 15:06:24 +0000 | |
commit | c9fcfd02a69170cedcd4cf2e66826f246dff6267 (patch) | |
tree | 2bc39091ec4dbc71bad37efafde41d13d168f0ca | |
parent | 782fb716122d37dc4c4d7482afb21f6e68be04b4 (diff) |
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
-rw-r--r-- | compiler/optimizing/graph_visualizer.cc | 47 | ||||
-rw-r--r-- | compiler/optimizing/graph_visualizer.h | 6 | ||||
-rw-r--r-- | compiler/optimizing/nodes.cc | 38 | ||||
-rw-r--r-- | compiler/optimizing/nodes.h | 1 | ||||
-rw-r--r-- | compiler/optimizing/optimizing_compiler.cc | 2 |
5 files changed, 77 insertions, 17 deletions
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<HGraphVisualizerDisassembler> 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 diff --git a/compiler/optimizing/graph_visualizer.h b/compiler/optimizing/graph_visualizer.h index e01d03c19c..b83e88740c 100644 --- a/compiler/optimizing/graph_visualizer.h +++ b/compiler/optimizing/graph_visualizer.h @@ -101,7 +101,7 @@ class HGraphVisualizer : public ValueObject { public: HGraphVisualizer(std::ostream* output, HGraph* graph, - const CodeGenerator& codegen); + const CodeGenerator* codegen); void PrintHeader(const char* method_name) const; void DumpGraph(const char* pass_name, bool is_after_pass, bool graph_in_bad_state) const; @@ -112,10 +112,12 @@ class HGraphVisualizer : public ValueObject { // method attributes is used. Such empty blocks don't break the c1visualizer parser. static std::string InsertMetaDataAsCompilationBlock(const std::string& meta_data); + static void DumpInstruction(std::ostream* output, HGraph* graph, HInstruction* instruction); + private: std::ostream* const output_; HGraph* const graph_; - const CodeGenerator& codegen_; + const CodeGenerator* codegen_; DISALLOW_COPY_AND_ASSIGN(HGraphVisualizer); }; diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc index e3e4589b63..d57eaf0b60 100644 --- a/compiler/optimizing/nodes.cc +++ b/compiler/optimizing/nodes.cc @@ -1312,6 +1312,44 @@ void HEnvironment::ReplaceInput(HInstruction* replacement, size_t index) { orig_instr->FixUpUserRecordsAfterEnvUseRemoval(before_use_node); } +std::ostream& HInstruction::Dump(std::ostream& os, bool dump_args) { + HGraph* graph = GetBlock()->GetGraph(); + HGraphVisualizer::DumpInstruction(&os, graph, this); + if (dump_args) { + // Allocate memory from local ScopedArenaAllocator. + ScopedArenaAllocator allocator(graph->GetArenaStack()); + // Instructions that we already visited. We print each instruction only once. + ArenaBitVector visited( + &allocator, graph->GetCurrentInstructionId(), /* expandable= */ false, kArenaAllocMisc); + visited.ClearAllBits(); + visited.SetBit(GetId()); + // Keep a queue of instructions with their indentations. + ScopedArenaDeque<std::pair<HInstruction*, size_t>> queue(allocator.Adapter(kArenaAllocMisc)); + auto add_args = [&queue](HInstruction* instruction, size_t indentation) { + for (HInstruction* arg : ReverseRange(instruction->GetInputs())) { + queue.emplace_front(arg, indentation); + } + }; + add_args(this, /*indentation=*/ 1u); + while (!queue.empty()) { + HInstruction* instruction; + size_t indentation; + std::tie(instruction, indentation) = queue.front(); + queue.pop_front(); + if (!visited.IsBitSet(instruction->GetId())) { + visited.SetBit(instruction->GetId()); + os << '\n'; + for (size_t i = 0; i != indentation; ++i) { + os << " "; + } + HGraphVisualizer::DumpInstruction(&os, graph, instruction); + add_args(instruction, indentation + 1u); + } + } + } + return os; +} + HInstruction* HInstruction::GetNextDisregardingMoves() const { HInstruction* next = GetNext(); while (next != nullptr && next->IsParallelMove()) { diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h index d15e40aeff..125f86be81 100644 --- a/compiler/optimizing/nodes.h +++ b/compiler/optimizing/nodes.h @@ -2145,6 +2145,7 @@ class HInstruction : public ArenaObject<kArenaAllocInstruction> { virtual ~HInstruction() {} + std::ostream& Dump(std::ostream& os, bool dump_args = false); HInstruction* GetNext() const { return next_; } HInstruction* GetPrevious() const { return previous_; } diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc index b7e9d63e2f..ac241aa9c9 100644 --- a/compiler/optimizing/optimizing_compiler.cc +++ b/compiler/optimizing/optimizing_compiler.cc @@ -117,7 +117,7 @@ class PassObserver : public ValueObject { visualizer_oss_(), visualizer_output_(visualizer_output), visualizer_enabled_(!compiler_options.GetDumpCfgFileName().empty()), - visualizer_(&visualizer_oss_, graph, *codegen), + visualizer_(&visualizer_oss_, graph, codegen), codegen_(codegen), visualizer_dump_mutex_(dump_mutex), graph_in_bad_state_(false) { |