blob: 5c5042e20f2d857484d8ecbb4e7040713272db3c [file] [log] [blame]
Nicolas Geoffrayf635e632014-05-14 09:43:38 +01001/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "graph_visualizer.h"
18
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010019#include "code_generator.h"
Nicolas Geoffrayf635e632014-05-14 09:43:38 +010020#include "driver/dex_compilation_unit.h"
21#include "nodes.h"
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +010022#include "ssa_liveness_analysis.h"
Nicolas Geoffrayf635e632014-05-14 09:43:38 +010023
24namespace art {
25
26/**
27 * HGraph visitor to generate a file suitable for the c1visualizer tool and IRHydra.
28 */
29class HGraphVisualizerPrinter : public HGraphVisitor {
30 public:
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010031 HGraphVisualizerPrinter(HGraph* graph, std::ostream& output, const CodeGenerator& codegen)
32 : HGraphVisitor(graph), output_(output), codegen_(codegen), indent_(0) {}
Nicolas Geoffrayf635e632014-05-14 09:43:38 +010033
34 void StartTag(const char* name) {
35 AddIndent();
36 output_ << "begin_" << name << std::endl;
37 indent_++;
38 }
39
40 void EndTag(const char* name) {
41 indent_--;
42 AddIndent();
43 output_ << "end_" << name << std::endl;
44 }
45
46 void PrintProperty(const char* name, const char* property) {
47 AddIndent();
48 output_ << name << " \"" << property << "\"" << std::endl;
49 }
50
51 void PrintProperty(const char* name, const char* property, int id) {
52 AddIndent();
53 output_ << name << " \"" << property << id << "\"" << std::endl;
54 }
55
56 void PrintEmptyProperty(const char* name) {
57 AddIndent();
58 output_ << name << std::endl;
59 }
60
61 void PrintTime(const char* name) {
62 AddIndent();
63 output_ << name << " " << time(NULL) << std::endl;
64 }
65
66 void PrintInt(const char* name, int value) {
67 AddIndent();
68 output_ << name << " " << value << std::endl;
69 }
70
71 void AddIndent() {
72 for (size_t i = 0; i < indent_; ++i) {
73 output_ << " ";
74 }
75 }
76
77 void PrintPredecessors(HBasicBlock* block) {
78 AddIndent();
79 output_ << "predecessors";
80 for (size_t i = 0, e = block->GetPredecessors().Size(); i < e; ++i) {
81 HBasicBlock* predecessor = block->GetPredecessors().Get(i);
82 output_ << " \"B" << predecessor->GetBlockId() << "\" ";
83 }
84 output_<< std::endl;
85 }
86
87 void PrintSuccessors(HBasicBlock* block) {
88 AddIndent();
89 output_ << "successors";
90 for (size_t i = 0, e = block->GetSuccessors().Size(); i < e; ++i) {
91 HBasicBlock* successor = block->GetSuccessors().Get(i);
92 output_ << " \"B" << successor->GetBlockId() << "\" ";
93 }
94 output_<< std::endl;
95 }
96
97
98 void VisitInstruction(HInstruction* instruction) {
99 output_ << instruction->DebugName();
100 if (instruction->InputCount() > 0) {
101 output_ << " [ ";
102 for (HInputIterator inputs(instruction); !inputs.Done(); inputs.Advance()) {
103 output_ << "v" << inputs.Current()->GetId() << " ";
104 }
105 output_ << "]";
106 }
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100107 if (instruction->GetLifetimePosition() != kNoLifetime) {
108 output_ << " (liveness: " << instruction->GetLifetimePosition();
109 if (instruction->HasLiveInterval()) {
110 output_ << " ";
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100111 const LiveInterval& interval = *instruction->GetLiveInterval();
112 interval.Dump(output_);
113 if (interval.HasRegister()) {
114 int reg = interval.GetRegister();
115 output_ << " ";
116 if (instruction->GetType() == Primitive::kPrimFloat
117 || instruction->GetType() == Primitive::kPrimDouble) {
118 codegen_.DumpFloatingPointRegister(output_, reg);
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100119 } else {
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100120 codegen_.DumpCoreRegister(output_, reg);
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100121 }
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100122 }
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100123 }
124 output_ << ")";
125 }
Nicolas Geoffrayf635e632014-05-14 09:43:38 +0100126 }
127
128 void PrintInstructions(const HInstructionList& list) {
129 const char* kEndInstructionMarker = "<|@";
130 for (HInstructionIterator it(list); !it.Done(); it.Advance()) {
131 HInstruction* instruction = it.Current();
132 AddIndent();
133 int bci = 0;
134 output_ << bci << " " << instruction->NumberOfUses() << " v" << instruction->GetId() << " ";
135 instruction->Accept(this);
136 output_ << kEndInstructionMarker << std::endl;
137 }
138 }
139
140 void Run(const char* pass_name) {
141 StartTag("cfg");
142 PrintProperty("name", pass_name);
143 VisitInsertionOrder();
144 EndTag("cfg");
145 }
146
147 void VisitBasicBlock(HBasicBlock* block) {
148 StartTag("block");
149 PrintProperty("name", "B", block->GetBlockId());
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100150 if (block->GetLifetimeStart() != kNoLifetime) {
151 // Piggy back on these fields to show the lifetime of the block.
152 PrintInt("from_bci", block->GetLifetimeStart());
153 PrintInt("to_bci", block->GetLifetimeEnd());
154 } else {
155 PrintInt("from_bci", -1);
156 PrintInt("to_bci", -1);
157 }
Nicolas Geoffrayf635e632014-05-14 09:43:38 +0100158 PrintPredecessors(block);
159 PrintSuccessors(block);
160 PrintEmptyProperty("xhandlers");
161 PrintEmptyProperty("flags");
162 if (block->GetDominator() != nullptr) {
163 PrintProperty("dominator", "B", block->GetDominator()->GetBlockId());
164 }
165
166 StartTag("states");
167 StartTag("locals");
168 PrintInt("size", 0);
169 PrintProperty("method", "None");
170 for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
171 AddIndent();
172 HInstruction* instruction = it.Current();
173 output_ << instruction->GetId() << " v" << instruction->GetId() << "[ ";
174 for (HInputIterator inputs(instruction); !inputs.Done(); inputs.Advance()) {
175 output_ << inputs.Current()->GetId() << " ";
176 }
177 output_ << "]" << std::endl;
178 }
179 EndTag("locals");
180 EndTag("states");
181
182 StartTag("HIR");
183 PrintInstructions(block->GetPhis());
184 PrintInstructions(block->GetInstructions());
185 EndTag("HIR");
186 EndTag("block");
187 }
188
189 private:
190 std::ostream& output_;
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100191 const CodeGenerator& codegen_;
Nicolas Geoffrayf635e632014-05-14 09:43:38 +0100192 size_t indent_;
193
194 DISALLOW_COPY_AND_ASSIGN(HGraphVisualizerPrinter);
195};
196
197HGraphVisualizer::HGraphVisualizer(std::ostream* output,
198 HGraph* graph,
199 const char* string_filter,
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100200 const CodeGenerator& codegen,
Nicolas Geoffrayf635e632014-05-14 09:43:38 +0100201 const DexCompilationUnit& cu)
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100202 : output_(output), graph_(graph), codegen_(codegen), is_enabled_(false) {
Nicolas Geoffrayf635e632014-05-14 09:43:38 +0100203 if (output == nullptr) {
204 return;
205 }
206 std::string pretty_name = PrettyMethod(cu.GetDexMethodIndex(), *cu.GetDexFile());
207 if (pretty_name.find(string_filter) == std::string::npos) {
208 return;
209 }
210
211 is_enabled_ = true;
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100212 HGraphVisualizerPrinter printer(graph, *output_, codegen_);
Nicolas Geoffrayf635e632014-05-14 09:43:38 +0100213 printer.StartTag("compilation");
214 printer.PrintProperty("name", pretty_name.c_str());
215 printer.PrintProperty("method", pretty_name.c_str());
216 printer.PrintTime("date");
217 printer.EndTag("compilation");
218}
219
Nicolas Geoffray0d3f5782014-05-14 09:43:38 +0100220HGraphVisualizer::HGraphVisualizer(std::ostream* output,
221 HGraph* graph,
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100222 const CodeGenerator& codegen,
Nicolas Geoffray0d3f5782014-05-14 09:43:38 +0100223 const char* name)
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100224 : output_(output), graph_(graph), codegen_(codegen), is_enabled_(false) {
Nicolas Geoffray0d3f5782014-05-14 09:43:38 +0100225 if (output == nullptr) {
226 return;
227 }
228
229 is_enabled_ = true;
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100230 HGraphVisualizerPrinter printer(graph, *output_, codegen_);
Nicolas Geoffray0d3f5782014-05-14 09:43:38 +0100231 printer.StartTag("compilation");
232 printer.PrintProperty("name", name);
233 printer.PrintProperty("method", name);
234 printer.PrintTime("date");
235 printer.EndTag("compilation");
236}
237
Nicolas Geoffrayf635e632014-05-14 09:43:38 +0100238void HGraphVisualizer::DumpGraph(const char* pass_name) {
239 if (!is_enabled_) {
240 return;
241 }
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100242 HGraphVisualizerPrinter printer(graph_, *output_, codegen_);
Nicolas Geoffrayf635e632014-05-14 09:43:38 +0100243 printer.Run(pass_name);
244}
245
246} // namespace art