blob: 4ed2156241171f94129cd3f7c40a6f4dff4e08f9 [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 Geoffray86dbb9a2014-06-04 11:12:39 +010031 HGraphVisualizerPrinter(HGraph* graph,
32 std::ostream& output,
33 const char* pass_name,
34 const CodeGenerator& codegen)
35 : HGraphVisitor(graph),
36 output_(output),
37 pass_name_(pass_name),
38 codegen_(codegen),
39 indent_(0) {}
Nicolas Geoffrayf635e632014-05-14 09:43:38 +010040
41 void StartTag(const char* name) {
42 AddIndent();
43 output_ << "begin_" << name << std::endl;
44 indent_++;
45 }
46
47 void EndTag(const char* name) {
48 indent_--;
49 AddIndent();
50 output_ << "end_" << name << std::endl;
51 }
52
53 void PrintProperty(const char* name, const char* property) {
54 AddIndent();
55 output_ << name << " \"" << property << "\"" << std::endl;
56 }
57
58 void PrintProperty(const char* name, const char* property, int id) {
59 AddIndent();
60 output_ << name << " \"" << property << id << "\"" << std::endl;
61 }
62
63 void PrintEmptyProperty(const char* name) {
64 AddIndent();
65 output_ << name << std::endl;
66 }
67
68 void PrintTime(const char* name) {
69 AddIndent();
70 output_ << name << " " << time(NULL) << std::endl;
71 }
72
73 void PrintInt(const char* name, int value) {
74 AddIndent();
75 output_ << name << " " << value << std::endl;
76 }
77
78 void AddIndent() {
79 for (size_t i = 0; i < indent_; ++i) {
80 output_ << " ";
81 }
82 }
83
Nicolas Geoffrayb09aacb2014-09-17 18:21:53 +010084 char GetTypeId(Primitive::Type type) {
Nicolas Geoffray18efde52014-09-22 15:51:11 +010085 // Note that Primitive::Descriptor would not work for us
86 // because it does not handle reference types (that is kPrimNot).
Nicolas Geoffrayb09aacb2014-09-17 18:21:53 +010087 switch (type) {
88 case Primitive::kPrimBoolean: return 'z';
89 case Primitive::kPrimByte: return 'b';
90 case Primitive::kPrimChar: return 'c';
91 case Primitive::kPrimShort: return 's';
92 case Primitive::kPrimInt: return 'i';
93 case Primitive::kPrimLong: return 'j';
94 case Primitive::kPrimFloat: return 'f';
95 case Primitive::kPrimDouble: return 'd';
96 case Primitive::kPrimNot: return 'l';
97 case Primitive::kPrimVoid: return 'v';
98 }
99 LOG(FATAL) << "Unreachable";
100 return 'v';
101 }
102
Nicolas Geoffrayf635e632014-05-14 09:43:38 +0100103 void PrintPredecessors(HBasicBlock* block) {
104 AddIndent();
105 output_ << "predecessors";
106 for (size_t i = 0, e = block->GetPredecessors().Size(); i < e; ++i) {
107 HBasicBlock* predecessor = block->GetPredecessors().Get(i);
108 output_ << " \"B" << predecessor->GetBlockId() << "\" ";
109 }
110 output_<< std::endl;
111 }
112
113 void PrintSuccessors(HBasicBlock* block) {
114 AddIndent();
115 output_ << "successors";
116 for (size_t i = 0, e = block->GetSuccessors().Size(); i < e; ++i) {
117 HBasicBlock* successor = block->GetSuccessors().Get(i);
118 output_ << " \"B" << successor->GetBlockId() << "\" ";
119 }
120 output_<< std::endl;
121 }
122
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100123 void DumpLocation(Location location) {
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100124 if (location.IsRegister()) {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100125 codegen_.DumpCoreRegister(output_, location.reg());
126 } else if (location.IsFpuRegister()) {
127 codegen_.DumpFloatingPointRegister(output_, location.reg());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100128 } else if (location.IsConstant()) {
129 output_ << "constant";
Nicolas Geoffray18efde52014-09-22 15:51:11 +0100130 HConstant* constant = location.GetConstant();
131 if (constant->IsIntConstant()) {
132 output_ << " " << constant->AsIntConstant()->GetValue();
133 } else if (constant->IsLongConstant()) {
134 output_ << " " << constant->AsLongConstant()->GetValue();
135 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100136 } else if (location.IsInvalid()) {
137 output_ << "invalid";
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100138 } else if (location.IsStackSlot()) {
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100139 output_ << location.GetStackIndex() << "(sp)";
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100140 } else {
141 DCHECK(location.IsDoubleStackSlot());
142 output_ << "2x" << location.GetStackIndex() << "(sp)";
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100143 }
144 }
145
146 void VisitParallelMove(HParallelMove* instruction) {
147 output_ << instruction->DebugName();
148 output_ << " (";
149 for (size_t i = 0, e = instruction->NumMoves(); i < e; ++i) {
150 MoveOperands* move = instruction->MoveOperandsAt(i);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100151 DumpLocation(move->GetSource());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100152 output_ << " -> ";
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100153 DumpLocation(move->GetDestination());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100154 if (i + 1 != e) {
155 output_ << ", ";
156 }
157 }
158 output_ << ")";
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +0100159 output_ << " (liveness: " << instruction->GetLifetimePosition() << ")";
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100160 }
Nicolas Geoffrayf635e632014-05-14 09:43:38 +0100161
162 void VisitInstruction(HInstruction* instruction) {
163 output_ << instruction->DebugName();
164 if (instruction->InputCount() > 0) {
165 output_ << " [ ";
166 for (HInputIterator inputs(instruction); !inputs.Done(); inputs.Advance()) {
Nicolas Geoffrayb09aacb2014-09-17 18:21:53 +0100167 output_ << GetTypeId(inputs.Current()->GetType()) << inputs.Current()->GetId() << " ";
Nicolas Geoffrayf635e632014-05-14 09:43:38 +0100168 }
169 output_ << "]";
170 }
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100171 if (pass_name_ == kLivenessPassName && instruction->GetLifetimePosition() != kNoLifetime) {
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100172 output_ << " (liveness: " << instruction->GetLifetimePosition();
173 if (instruction->HasLiveInterval()) {
174 output_ << " ";
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100175 const LiveInterval& interval = *instruction->GetLiveInterval();
176 interval.Dump(output_);
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100177 }
178 output_ << ")";
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100179 } else if (pass_name_ == kRegisterAllocatorPassName) {
180 LocationSummary* locations = instruction->GetLocations();
181 if (locations != nullptr) {
182 output_ << " ( ";
183 for (size_t i = 0; i < instruction->InputCount(); ++i) {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100184 DumpLocation(locations->InAt(i));
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100185 output_ << " ";
186 }
187 output_ << ")";
188 if (locations->Out().IsValid()) {
189 output_ << " -> ";
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100190 DumpLocation(locations->Out());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100191 }
192 }
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +0100193 output_ << " (liveness: " << instruction->GetLifetimePosition() << ")";
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100194 }
Nicolas Geoffrayf635e632014-05-14 09:43:38 +0100195 }
196
197 void PrintInstructions(const HInstructionList& list) {
198 const char* kEndInstructionMarker = "<|@";
199 for (HInstructionIterator it(list); !it.Done(); it.Advance()) {
200 HInstruction* instruction = it.Current();
201 AddIndent();
202 int bci = 0;
Nicolas Geoffrayb09aacb2014-09-17 18:21:53 +0100203 output_ << bci << " " << instruction->NumberOfUses()
204 << " " << GetTypeId(instruction->GetType()) << instruction->GetId() << " ";
Nicolas Geoffrayf635e632014-05-14 09:43:38 +0100205 instruction->Accept(this);
206 output_ << kEndInstructionMarker << std::endl;
207 }
208 }
209
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100210 void Run() {
Nicolas Geoffrayf635e632014-05-14 09:43:38 +0100211 StartTag("cfg");
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100212 PrintProperty("name", pass_name_);
Nicolas Geoffrayf635e632014-05-14 09:43:38 +0100213 VisitInsertionOrder();
214 EndTag("cfg");
215 }
216
217 void VisitBasicBlock(HBasicBlock* block) {
218 StartTag("block");
219 PrintProperty("name", "B", block->GetBlockId());
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100220 if (block->GetLifetimeStart() != kNoLifetime) {
221 // Piggy back on these fields to show the lifetime of the block.
222 PrintInt("from_bci", block->GetLifetimeStart());
223 PrintInt("to_bci", block->GetLifetimeEnd());
224 } else {
225 PrintInt("from_bci", -1);
226 PrintInt("to_bci", -1);
227 }
Nicolas Geoffrayf635e632014-05-14 09:43:38 +0100228 PrintPredecessors(block);
229 PrintSuccessors(block);
230 PrintEmptyProperty("xhandlers");
231 PrintEmptyProperty("flags");
232 if (block->GetDominator() != nullptr) {
233 PrintProperty("dominator", "B", block->GetDominator()->GetBlockId());
234 }
235
236 StartTag("states");
237 StartTag("locals");
238 PrintInt("size", 0);
239 PrintProperty("method", "None");
240 for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
241 AddIndent();
242 HInstruction* instruction = it.Current();
Nicolas Geoffrayb09aacb2014-09-17 18:21:53 +0100243 output_ << instruction->GetId() << " " << GetTypeId(instruction->GetType())
244 << instruction->GetId() << "[ ";
Nicolas Geoffrayf635e632014-05-14 09:43:38 +0100245 for (HInputIterator inputs(instruction); !inputs.Done(); inputs.Advance()) {
246 output_ << inputs.Current()->GetId() << " ";
247 }
248 output_ << "]" << std::endl;
249 }
250 EndTag("locals");
251 EndTag("states");
252
253 StartTag("HIR");
254 PrintInstructions(block->GetPhis());
255 PrintInstructions(block->GetInstructions());
256 EndTag("HIR");
257 EndTag("block");
258 }
259
260 private:
261 std::ostream& output_;
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100262 const char* pass_name_;
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100263 const CodeGenerator& codegen_;
Nicolas Geoffrayf635e632014-05-14 09:43:38 +0100264 size_t indent_;
265
266 DISALLOW_COPY_AND_ASSIGN(HGraphVisualizerPrinter);
267};
268
269HGraphVisualizer::HGraphVisualizer(std::ostream* output,
270 HGraph* graph,
271 const char* string_filter,
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100272 const CodeGenerator& codegen,
Nicolas Geoffrayf635e632014-05-14 09:43:38 +0100273 const DexCompilationUnit& cu)
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100274 : output_(output), graph_(graph), codegen_(codegen), is_enabled_(false) {
Nicolas Geoffrayf635e632014-05-14 09:43:38 +0100275 if (output == nullptr) {
276 return;
277 }
278 std::string pretty_name = PrettyMethod(cu.GetDexMethodIndex(), *cu.GetDexFile());
279 if (pretty_name.find(string_filter) == std::string::npos) {
280 return;
281 }
282
283 is_enabled_ = true;
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100284 HGraphVisualizerPrinter printer(graph, *output_, "", codegen_);
Nicolas Geoffrayf635e632014-05-14 09:43:38 +0100285 printer.StartTag("compilation");
286 printer.PrintProperty("name", pretty_name.c_str());
287 printer.PrintProperty("method", pretty_name.c_str());
288 printer.PrintTime("date");
289 printer.EndTag("compilation");
290}
291
Nicolas Geoffray0d3f5782014-05-14 09:43:38 +0100292HGraphVisualizer::HGraphVisualizer(std::ostream* output,
293 HGraph* graph,
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100294 const CodeGenerator& codegen,
Nicolas Geoffray0d3f5782014-05-14 09:43:38 +0100295 const char* name)
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100296 : output_(output), graph_(graph), codegen_(codegen), is_enabled_(false) {
Nicolas Geoffray0d3f5782014-05-14 09:43:38 +0100297 if (output == nullptr) {
298 return;
299 }
300
301 is_enabled_ = true;
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100302 HGraphVisualizerPrinter printer(graph, *output_, "", codegen_);
Nicolas Geoffray0d3f5782014-05-14 09:43:38 +0100303 printer.StartTag("compilation");
304 printer.PrintProperty("name", name);
305 printer.PrintProperty("method", name);
306 printer.PrintTime("date");
307 printer.EndTag("compilation");
308}
309
Roland Levillain75be2832014-10-17 17:02:00 +0100310void HGraphVisualizer::DumpGraph(const char* pass_name) const {
Nicolas Geoffrayf635e632014-05-14 09:43:38 +0100311 if (!is_enabled_) {
312 return;
313 }
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100314 HGraphVisualizerPrinter printer(graph_, *output_, pass_name, codegen_);
315 printer.Run();
Nicolas Geoffrayf635e632014-05-14 09:43:38 +0100316}
317
318} // namespace art