blob: 9fd8d00839cb0b1c2fc7976f6ccdd238fdbebcf4 [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"
David Brazdila4b8c212015-05-07 09:59:30 +010020#include "dead_code_elimination.h"
Andreas Gampe7c3952f2015-02-19 18:21:24 -080021#include "licm.h"
Nicolas Geoffrayf635e632014-05-14 09:43:38 +010022#include "nodes.h"
Nicolas Geoffray82091da2015-01-26 10:02:45 +000023#include "optimization.h"
Nicolas Geoffray7cb499b2015-06-17 11:35:11 +010024#include "reference_type_propagation.h"
Andreas Gampe7c3952f2015-02-19 18:21:24 -080025#include "register_allocator.h"
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +010026#include "ssa_liveness_analysis.h"
Nicolas Geoffrayf635e632014-05-14 09:43:38 +010027
David Brazdilc74652862015-05-13 17:50:09 +010028#include <cctype>
29#include <sstream>
30
Nicolas Geoffrayf635e632014-05-14 09:43:38 +010031namespace art {
32
David Brazdilc74652862015-05-13 17:50:09 +010033static bool HasWhitespace(const char* str) {
34 DCHECK(str != nullptr);
35 while (str[0] != 0) {
36 if (isspace(str[0])) {
37 return true;
38 }
39 str++;
40 }
41 return false;
42}
43
44class StringList {
45 public:
David Brazdilc7a24852015-05-15 16:44:05 +010046 enum Format {
47 kArrayBrackets,
48 kSetBrackets,
49 };
50
David Brazdilc74652862015-05-13 17:50:09 +010051 // Create an empty list
David Brazdilf1a9ff72015-05-18 16:04:53 +010052 explicit StringList(Format format = kArrayBrackets) : format_(format), is_empty_(true) {}
David Brazdilc74652862015-05-13 17:50:09 +010053
54 // Construct StringList from a linked list. List element class T
55 // must provide methods `GetNext` and `Dump`.
56 template<class T>
David Brazdilc7a24852015-05-15 16:44:05 +010057 explicit StringList(T* first_entry, Format format = kArrayBrackets) : StringList(format) {
David Brazdilc74652862015-05-13 17:50:09 +010058 for (T* current = first_entry; current != nullptr; current = current->GetNext()) {
59 current->Dump(NewEntryStream());
60 }
61 }
62
63 std::ostream& NewEntryStream() {
64 if (is_empty_) {
65 is_empty_ = false;
66 } else {
David Brazdilc57397b2015-05-15 16:01:59 +010067 sstream_ << ",";
David Brazdilc74652862015-05-13 17:50:09 +010068 }
69 return sstream_;
70 }
71
72 private:
David Brazdilc7a24852015-05-15 16:44:05 +010073 Format format_;
David Brazdilc74652862015-05-13 17:50:09 +010074 bool is_empty_;
75 std::ostringstream sstream_;
76
77 friend std::ostream& operator<<(std::ostream& os, const StringList& list);
78};
79
80std::ostream& operator<<(std::ostream& os, const StringList& list) {
David Brazdilc7a24852015-05-15 16:44:05 +010081 switch (list.format_) {
82 case StringList::kArrayBrackets: return os << "[" << list.sstream_.str() << "]";
83 case StringList::kSetBrackets: return os << "{" << list.sstream_.str() << "}";
84 default:
85 LOG(FATAL) << "Invalid StringList format";
86 UNREACHABLE();
87 }
David Brazdilc74652862015-05-13 17:50:09 +010088}
89
Nicolas Geoffrayf635e632014-05-14 09:43:38 +010090/**
91 * HGraph visitor to generate a file suitable for the c1visualizer tool and IRHydra.
92 */
93class HGraphVisualizerPrinter : public HGraphVisitor {
94 public:
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +010095 HGraphVisualizerPrinter(HGraph* graph,
96 std::ostream& output,
97 const char* pass_name,
Nicolas Geoffray840e5462015-01-07 16:01:24 +000098 bool is_after_pass,
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +010099 const CodeGenerator& codegen)
100 : HGraphVisitor(graph),
101 output_(output),
102 pass_name_(pass_name),
Nicolas Geoffray840e5462015-01-07 16:01:24 +0000103 is_after_pass_(is_after_pass),
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100104 codegen_(codegen),
105 indent_(0) {}
Nicolas Geoffrayf635e632014-05-14 09:43:38 +0100106
107 void StartTag(const char* name) {
108 AddIndent();
109 output_ << "begin_" << name << std::endl;
110 indent_++;
111 }
112
113 void EndTag(const char* name) {
114 indent_--;
115 AddIndent();
116 output_ << "end_" << name << std::endl;
117 }
118
119 void PrintProperty(const char* name, const char* property) {
120 AddIndent();
121 output_ << name << " \"" << property << "\"" << std::endl;
122 }
123
124 void PrintProperty(const char* name, const char* property, int id) {
125 AddIndent();
126 output_ << name << " \"" << property << id << "\"" << std::endl;
127 }
128
129 void PrintEmptyProperty(const char* name) {
130 AddIndent();
131 output_ << name << std::endl;
132 }
133
134 void PrintTime(const char* name) {
135 AddIndent();
Jean Christophe Beyler0ada95d2014-12-04 11:20:20 -0800136 output_ << name << " " << time(nullptr) << std::endl;
Nicolas Geoffrayf635e632014-05-14 09:43:38 +0100137 }
138
139 void PrintInt(const char* name, int value) {
140 AddIndent();
141 output_ << name << " " << value << std::endl;
142 }
143
144 void AddIndent() {
145 for (size_t i = 0; i < indent_; ++i) {
146 output_ << " ";
147 }
148 }
149
Nicolas Geoffrayb09aacb2014-09-17 18:21:53 +0100150 char GetTypeId(Primitive::Type type) {
Nicolas Geoffray18efde52014-09-22 15:51:11 +0100151 // Note that Primitive::Descriptor would not work for us
152 // because it does not handle reference types (that is kPrimNot).
Nicolas Geoffrayb09aacb2014-09-17 18:21:53 +0100153 switch (type) {
154 case Primitive::kPrimBoolean: return 'z';
155 case Primitive::kPrimByte: return 'b';
156 case Primitive::kPrimChar: return 'c';
157 case Primitive::kPrimShort: return 's';
158 case Primitive::kPrimInt: return 'i';
159 case Primitive::kPrimLong: return 'j';
160 case Primitive::kPrimFloat: return 'f';
161 case Primitive::kPrimDouble: return 'd';
162 case Primitive::kPrimNot: return 'l';
163 case Primitive::kPrimVoid: return 'v';
164 }
165 LOG(FATAL) << "Unreachable";
166 return 'v';
167 }
168
Nicolas Geoffrayf635e632014-05-14 09:43:38 +0100169 void PrintPredecessors(HBasicBlock* block) {
170 AddIndent();
171 output_ << "predecessors";
172 for (size_t i = 0, e = block->GetPredecessors().Size(); i < e; ++i) {
173 HBasicBlock* predecessor = block->GetPredecessors().Get(i);
174 output_ << " \"B" << predecessor->GetBlockId() << "\" ";
175 }
176 output_<< std::endl;
177 }
178
179 void PrintSuccessors(HBasicBlock* block) {
180 AddIndent();
181 output_ << "successors";
182 for (size_t i = 0, e = block->GetSuccessors().Size(); i < e; ++i) {
183 HBasicBlock* successor = block->GetSuccessors().Get(i);
184 output_ << " \"B" << successor->GetBlockId() << "\" ";
185 }
186 output_<< std::endl;
187 }
188
David Brazdilc74652862015-05-13 17:50:09 +0100189 void DumpLocation(std::ostream& stream, const Location& location) {
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100190 if (location.IsRegister()) {
David Brazdilc74652862015-05-13 17:50:09 +0100191 codegen_.DumpCoreRegister(stream, location.reg());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100192 } else if (location.IsFpuRegister()) {
David Brazdilc74652862015-05-13 17:50:09 +0100193 codegen_.DumpFloatingPointRegister(stream, location.reg());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100194 } else if (location.IsConstant()) {
David Brazdilc74652862015-05-13 17:50:09 +0100195 stream << "#";
Nicolas Geoffray18efde52014-09-22 15:51:11 +0100196 HConstant* constant = location.GetConstant();
197 if (constant->IsIntConstant()) {
David Brazdilc74652862015-05-13 17:50:09 +0100198 stream << constant->AsIntConstant()->GetValue();
Nicolas Geoffray18efde52014-09-22 15:51:11 +0100199 } else if (constant->IsLongConstant()) {
David Brazdilc74652862015-05-13 17:50:09 +0100200 stream << constant->AsLongConstant()->GetValue();
Nicolas Geoffray18efde52014-09-22 15:51:11 +0100201 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100202 } else if (location.IsInvalid()) {
David Brazdilc74652862015-05-13 17:50:09 +0100203 stream << "invalid";
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100204 } else if (location.IsStackSlot()) {
David Brazdilc74652862015-05-13 17:50:09 +0100205 stream << location.GetStackIndex() << "(sp)";
Nicolas Geoffray840e5462015-01-07 16:01:24 +0000206 } else if (location.IsFpuRegisterPair()) {
David Brazdilc74652862015-05-13 17:50:09 +0100207 codegen_.DumpFloatingPointRegister(stream, location.low());
208 stream << "|";
209 codegen_.DumpFloatingPointRegister(stream, location.high());
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +0000210 } else if (location.IsRegisterPair()) {
David Brazdilc74652862015-05-13 17:50:09 +0100211 codegen_.DumpCoreRegister(stream, location.low());
212 stream << "|";
213 codegen_.DumpCoreRegister(stream, location.high());
Mark Mendell09ed1a32015-03-25 08:30:06 -0400214 } else if (location.IsUnallocated()) {
David Brazdilc74652862015-05-13 17:50:09 +0100215 stream << "unallocated";
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100216 } else {
217 DCHECK(location.IsDoubleStackSlot());
David Brazdilc74652862015-05-13 17:50:09 +0100218 stream << "2x" << location.GetStackIndex() << "(sp)";
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100219 }
220 }
221
David Brazdilc74652862015-05-13 17:50:09 +0100222 std::ostream& StartAttributeStream(const char* name = nullptr) {
223 if (name == nullptr) {
224 output_ << " ";
225 } else {
226 DCHECK(!HasWhitespace(name)) << "Checker does not allow spaces in attributes";
227 output_ << " " << name << ":";
228 }
229 return output_;
230 }
231
David Brazdilb7e4a062014-12-29 15:35:02 +0000232 void VisitParallelMove(HParallelMove* instruction) OVERRIDE {
David Brazdilc74652862015-05-13 17:50:09 +0100233 StartAttributeStream("liveness") << instruction->GetLifetimePosition();
234 StringList moves;
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100235 for (size_t i = 0, e = instruction->NumMoves(); i < e; ++i) {
236 MoveOperands* move = instruction->MoveOperandsAt(i);
David Brazdilc74652862015-05-13 17:50:09 +0100237 std::ostream& str = moves.NewEntryStream();
238 DumpLocation(str, move->GetSource());
239 str << "->";
240 DumpLocation(str, move->GetDestination());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100241 }
David Brazdilc74652862015-05-13 17:50:09 +0100242 StartAttributeStream("moves") << moves;
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100243 }
Nicolas Geoffrayf635e632014-05-14 09:43:38 +0100244
David Brazdil36cf0952015-01-08 19:28:33 +0000245 void VisitIntConstant(HIntConstant* instruction) OVERRIDE {
David Brazdilc74652862015-05-13 17:50:09 +0100246 StartAttributeStream() << instruction->GetValue();
David Brazdilb7e4a062014-12-29 15:35:02 +0000247 }
248
David Brazdil36cf0952015-01-08 19:28:33 +0000249 void VisitLongConstant(HLongConstant* instruction) OVERRIDE {
David Brazdilc74652862015-05-13 17:50:09 +0100250 StartAttributeStream() << instruction->GetValue();
David Brazdilb7e4a062014-12-29 15:35:02 +0000251 }
252
David Brazdil36cf0952015-01-08 19:28:33 +0000253 void VisitFloatConstant(HFloatConstant* instruction) OVERRIDE {
David Brazdilc74652862015-05-13 17:50:09 +0100254 StartAttributeStream() << instruction->GetValue();
David Brazdilb7e4a062014-12-29 15:35:02 +0000255 }
256
David Brazdil36cf0952015-01-08 19:28:33 +0000257 void VisitDoubleConstant(HDoubleConstant* instruction) OVERRIDE {
David Brazdilc74652862015-05-13 17:50:09 +0100258 StartAttributeStream() << instruction->GetValue();
David Brazdilb7e4a062014-12-29 15:35:02 +0000259 }
260
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +0000261 void VisitPhi(HPhi* phi) OVERRIDE {
David Brazdilc74652862015-05-13 17:50:09 +0100262 StartAttributeStream("reg") << phi->GetRegNumber();
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +0000263 }
264
Calin Juravle27df7582015-04-17 19:12:31 +0100265 void VisitMemoryBarrier(HMemoryBarrier* barrier) OVERRIDE {
David Brazdilc74652862015-05-13 17:50:09 +0100266 StartAttributeStream("kind") << barrier->GetBarrierKind();
Calin Juravle27df7582015-04-17 19:12:31 +0100267 }
268
Calin Juravle0ba218d2015-05-19 18:46:01 +0100269 void VisitLoadClass(HLoadClass* load_cass) OVERRIDE {
270 StartAttributeStream("gen_clinit_check") << std::boolalpha
271 << load_cass->MustGenerateClinitCheck() << std::noboolalpha;
272 }
273
Guillaume "Vermeille" Sanchez9099ef72015-05-20 15:19:21 +0100274 void VisitCheckCast(HCheckCast* check_cast) OVERRIDE {
275 StartAttributeStream("must_do_null_check") << std::boolalpha
276 << check_cast->MustDoNullCheck() << std::noboolalpha;
277 }
278
279 void VisitInstanceOf(HInstanceOf* instance_of) OVERRIDE {
280 StartAttributeStream("must_do_null_check") << std::boolalpha
281 << instance_of->MustDoNullCheck() << std::noboolalpha;
282 }
283
Nicolas Geoffrayd23eeef2015-05-18 22:31:29 +0100284 void VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) OVERRIDE {
285 StartAttributeStream("dex_file_index") << invoke->GetDexMethodIndex();
286 StartAttributeStream("recursive") << std::boolalpha
287 << invoke->IsRecursive()
288 << std::noboolalpha;
289 }
290
Andreas Gampe7c3952f2015-02-19 18:21:24 -0800291 bool IsPass(const char* name) {
292 return strcmp(pass_name_, name) == 0;
293 }
294
David Brazdilb7e4a062014-12-29 15:35:02 +0000295 void PrintInstruction(HInstruction* instruction) {
Nicolas Geoffrayf635e632014-05-14 09:43:38 +0100296 output_ << instruction->DebugName();
297 if (instruction->InputCount() > 0) {
David Brazdilc74652862015-05-13 17:50:09 +0100298 StringList inputs;
299 for (HInputIterator it(instruction); !it.Done(); it.Advance()) {
300 inputs.NewEntryStream() << GetTypeId(it.Current()->GetType()) << it.Current()->GetId();
Nicolas Geoffrayf635e632014-05-14 09:43:38 +0100301 }
David Brazdilc74652862015-05-13 17:50:09 +0100302 StartAttributeStream() << inputs;
Nicolas Geoffrayf635e632014-05-14 09:43:38 +0100303 }
David Brazdilc74652862015-05-13 17:50:09 +0100304 instruction->Accept(this);
Zheng Xubb7a28a2015-01-09 14:40:47 +0800305 if (instruction->HasEnvironment()) {
David Brazdilc74652862015-05-13 17:50:09 +0100306 StringList envs;
Nicolas Geoffray0a23d742015-05-07 11:57:35 +0100307 for (HEnvironment* environment = instruction->GetEnvironment();
308 environment != nullptr;
309 environment = environment->GetParent()) {
David Brazdilc74652862015-05-13 17:50:09 +0100310 StringList vregs;
Nicolas Geoffray0a23d742015-05-07 11:57:35 +0100311 for (size_t i = 0, e = environment->Size(); i < e; ++i) {
312 HInstruction* insn = environment->GetInstructionAt(i);
313 if (insn != nullptr) {
David Brazdilc74652862015-05-13 17:50:09 +0100314 vregs.NewEntryStream() << GetTypeId(insn->GetType()) << insn->GetId();
Nicolas Geoffray0a23d742015-05-07 11:57:35 +0100315 } else {
David Brazdilc74652862015-05-13 17:50:09 +0100316 vregs.NewEntryStream() << "_";
Nicolas Geoffray0a23d742015-05-07 11:57:35 +0100317 }
Zheng Xubb7a28a2015-01-09 14:40:47 +0800318 }
David Brazdilc74652862015-05-13 17:50:09 +0100319 envs.NewEntryStream() << vregs;
Zheng Xubb7a28a2015-01-09 14:40:47 +0800320 }
David Brazdilc74652862015-05-13 17:50:09 +0100321 StartAttributeStream("env") << envs;
Zheng Xubb7a28a2015-01-09 14:40:47 +0800322 }
Andreas Gampe7c3952f2015-02-19 18:21:24 -0800323 if (IsPass(SsaLivenessAnalysis::kLivenessPassName)
David Brazdil5e8b1372015-01-23 14:39:08 +0000324 && is_after_pass_
325 && instruction->GetLifetimePosition() != kNoLifetime) {
David Brazdilc74652862015-05-13 17:50:09 +0100326 StartAttributeStream("liveness") << instruction->GetLifetimePosition();
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100327 if (instruction->HasLiveInterval()) {
David Brazdilc74652862015-05-13 17:50:09 +0100328 LiveInterval* interval = instruction->GetLiveInterval();
David Brazdilc7a24852015-05-15 16:44:05 +0100329 StartAttributeStream("ranges")
330 << StringList(interval->GetFirstRange(), StringList::kSetBrackets);
David Brazdilc74652862015-05-13 17:50:09 +0100331 StartAttributeStream("uses") << StringList(interval->GetFirstUse());
332 StartAttributeStream("env_uses") << StringList(interval->GetFirstEnvironmentUse());
333 StartAttributeStream("is_fixed") << interval->IsFixed();
334 StartAttributeStream("is_split") << interval->IsSplit();
335 StartAttributeStream("is_low") << interval->IsLowInterval();
336 StartAttributeStream("is_high") << interval->IsHighInterval();
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100337 }
Andreas Gampe7c3952f2015-02-19 18:21:24 -0800338 } else if (IsPass(RegisterAllocator::kRegisterAllocatorPassName) && is_after_pass_) {
David Brazdilc74652862015-05-13 17:50:09 +0100339 StartAttributeStream("liveness") << instruction->GetLifetimePosition();
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100340 LocationSummary* locations = instruction->GetLocations();
341 if (locations != nullptr) {
David Brazdilc74652862015-05-13 17:50:09 +0100342 StringList inputs;
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100343 for (size_t i = 0; i < instruction->InputCount(); ++i) {
David Brazdilc74652862015-05-13 17:50:09 +0100344 DumpLocation(inputs.NewEntryStream(), locations->InAt(i));
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100345 }
David Brazdilc74652862015-05-13 17:50:09 +0100346 std::ostream& attr = StartAttributeStream("locations");
347 attr << inputs << "->";
348 DumpLocation(attr, locations->Out());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100349 }
David Brazdila4b8c212015-05-07 09:59:30 +0100350 } else if (IsPass(LICM::kLoopInvariantCodeMotionPassName)
351 || IsPass(HDeadCodeElimination::kFinalDeadCodeEliminationPassName)) {
Nicolas Geoffray82091da2015-01-26 10:02:45 +0000352 HLoopInformation* info = instruction->GetBlock()->GetLoopInformation();
353 if (info == nullptr) {
David Brazdilc74652862015-05-13 17:50:09 +0100354 StartAttributeStream("loop") << "none";
Nicolas Geoffray82091da2015-01-26 10:02:45 +0000355 } else {
David Brazdilc74652862015-05-13 17:50:09 +0100356 StartAttributeStream("loop") << "B" << info->GetHeader()->GetBlockId();
Nicolas Geoffray82091da2015-01-26 10:02:45 +0000357 }
Nicolas Geoffray7cb499b2015-06-17 11:35:11 +0100358 } else if (IsPass(ReferenceTypePropagation::kReferenceTypePropagationPassName)
359 && is_after_pass_) {
360 if (instruction->GetType() == Primitive::kPrimNot) {
361 if (instruction->IsLoadClass()) {
Nicolas Geoffray66389fb2015-06-19 10:35:42 +0100362 ReferenceTypeInfo info = instruction->AsLoadClass()->GetLoadedClassRTI();
Nicolas Geoffray7cb499b2015-06-17 11:35:11 +0100363 ScopedObjectAccess soa(Thread::Current());
Nicolas Geoffray66389fb2015-06-19 10:35:42 +0100364 if (info.GetTypeHandle().GetReference() != nullptr) {
365 StartAttributeStream("klass") << info.GetTypeHandle().Get();
366 } else {
367 StartAttributeStream("klass") << "unresolved";
368 }
Nicolas Geoffray7cb499b2015-06-17 11:35:11 +0100369 } else {
370 ReferenceTypeInfo info = instruction->GetReferenceTypeInfo();
371 if (info.IsTop()) {
372 StartAttributeStream("klass") << "java.lang.Object";
373 } else {
374 ScopedObjectAccess soa(Thread::Current());
375 StartAttributeStream("klass") << PrettyClass(info.GetTypeHandle().Get());
376 }
377 StartAttributeStream("exact") << std::boolalpha << info.IsExact() << std::noboolalpha;
378 }
379 }
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100380 }
Nicolas Geoffrayf635e632014-05-14 09:43:38 +0100381 }
382
383 void PrintInstructions(const HInstructionList& list) {
384 const char* kEndInstructionMarker = "<|@";
385 for (HInstructionIterator it(list); !it.Done(); it.Advance()) {
386 HInstruction* instruction = it.Current();
Nicolas Geoffrayf635e632014-05-14 09:43:38 +0100387 int bci = 0;
David Brazdilea55b932015-01-27 17:12:29 +0000388 size_t num_uses = 0;
389 for (HUseIterator<HInstruction*> use_it(instruction->GetUses());
390 !use_it.Done();
391 use_it.Advance()) {
392 ++num_uses;
393 }
394 AddIndent();
395 output_ << bci << " " << num_uses << " "
396 << GetTypeId(instruction->GetType()) << instruction->GetId() << " ";
David Brazdilb7e4a062014-12-29 15:35:02 +0000397 PrintInstruction(instruction);
David Brazdilc74652862015-05-13 17:50:09 +0100398 output_ << " " << kEndInstructionMarker << std::endl;
Nicolas Geoffrayf635e632014-05-14 09:43:38 +0100399 }
400 }
401
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100402 void Run() {
Nicolas Geoffrayf635e632014-05-14 09:43:38 +0100403 StartTag("cfg");
Nicolas Geoffray840e5462015-01-07 16:01:24 +0000404 std::string pass_desc = std::string(pass_name_) + (is_after_pass_ ? " (after)" : " (before)");
405 PrintProperty("name", pass_desc.c_str());
Nicolas Geoffrayf635e632014-05-14 09:43:38 +0100406 VisitInsertionOrder();
407 EndTag("cfg");
408 }
409
David Brazdilb7e4a062014-12-29 15:35:02 +0000410 void VisitBasicBlock(HBasicBlock* block) OVERRIDE {
Nicolas Geoffrayf635e632014-05-14 09:43:38 +0100411 StartTag("block");
412 PrintProperty("name", "B", block->GetBlockId());
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100413 if (block->GetLifetimeStart() != kNoLifetime) {
414 // Piggy back on these fields to show the lifetime of the block.
415 PrintInt("from_bci", block->GetLifetimeStart());
416 PrintInt("to_bci", block->GetLifetimeEnd());
417 } else {
418 PrintInt("from_bci", -1);
419 PrintInt("to_bci", -1);
420 }
Nicolas Geoffrayf635e632014-05-14 09:43:38 +0100421 PrintPredecessors(block);
422 PrintSuccessors(block);
423 PrintEmptyProperty("xhandlers");
424 PrintEmptyProperty("flags");
425 if (block->GetDominator() != nullptr) {
426 PrintProperty("dominator", "B", block->GetDominator()->GetBlockId());
427 }
428
429 StartTag("states");
430 StartTag("locals");
431 PrintInt("size", 0);
432 PrintProperty("method", "None");
433 for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
434 AddIndent();
435 HInstruction* instruction = it.Current();
Nicolas Geoffrayb09aacb2014-09-17 18:21:53 +0100436 output_ << instruction->GetId() << " " << GetTypeId(instruction->GetType())
437 << instruction->GetId() << "[ ";
Nicolas Geoffrayf635e632014-05-14 09:43:38 +0100438 for (HInputIterator inputs(instruction); !inputs.Done(); inputs.Advance()) {
439 output_ << inputs.Current()->GetId() << " ";
440 }
441 output_ << "]" << std::endl;
442 }
443 EndTag("locals");
444 EndTag("states");
445
446 StartTag("HIR");
447 PrintInstructions(block->GetPhis());
448 PrintInstructions(block->GetInstructions());
449 EndTag("HIR");
450 EndTag("block");
451 }
452
453 private:
454 std::ostream& output_;
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100455 const char* pass_name_;
Nicolas Geoffray840e5462015-01-07 16:01:24 +0000456 const bool is_after_pass_;
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100457 const CodeGenerator& codegen_;
Nicolas Geoffrayf635e632014-05-14 09:43:38 +0100458 size_t indent_;
459
460 DISALLOW_COPY_AND_ASSIGN(HGraphVisualizerPrinter);
461};
462
463HGraphVisualizer::HGraphVisualizer(std::ostream* output,
464 HGraph* graph,
David Brazdil62e074f2015-04-07 18:09:37 +0100465 const CodeGenerator& codegen)
466 : output_(output), graph_(graph), codegen_(codegen) {}
Nicolas Geoffrayf635e632014-05-14 09:43:38 +0100467
David Brazdil62e074f2015-04-07 18:09:37 +0100468void HGraphVisualizer::PrintHeader(const char* method_name) const {
469 DCHECK(output_ != nullptr);
Nicolas Geoffray840e5462015-01-07 16:01:24 +0000470 HGraphVisualizerPrinter printer(graph_, *output_, "", true, codegen_);
Nicolas Geoffrayf635e632014-05-14 09:43:38 +0100471 printer.StartTag("compilation");
Nicolas Geoffraye53798a2014-12-01 10:31:54 +0000472 printer.PrintProperty("name", method_name);
473 printer.PrintProperty("method", method_name);
Nicolas Geoffray0d3f5782014-05-14 09:43:38 +0100474 printer.PrintTime("date");
475 printer.EndTag("compilation");
476}
477
David Brazdilee690a32014-12-01 17:04:16 +0000478void HGraphVisualizer::DumpGraph(const char* pass_name, bool is_after_pass) const {
David Brazdil5e8b1372015-01-23 14:39:08 +0000479 DCHECK(output_ != nullptr);
480 if (!graph_->GetBlocks().IsEmpty()) {
Nicolas Geoffray840e5462015-01-07 16:01:24 +0000481 HGraphVisualizerPrinter printer(graph_, *output_, pass_name, is_after_pass, codegen_);
David Brazdilee690a32014-12-01 17:04:16 +0000482 printer.Run();
Nicolas Geoffrayf635e632014-05-14 09:43:38 +0100483 }
Nicolas Geoffrayf635e632014-05-14 09:43:38 +0100484}
485
486} // namespace art