blob: be287558e9db17d0f4a0e3d5db700aee287391bb [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"
Andreas Gampe7c3952f2015-02-19 18:21:24 -080024#include "register_allocator.h"
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +010025#include "ssa_liveness_analysis.h"
Nicolas Geoffrayf635e632014-05-14 09:43:38 +010026
David Brazdilc74652862015-05-13 17:50:09 +010027#include <cctype>
28#include <sstream>
29
Nicolas Geoffrayf635e632014-05-14 09:43:38 +010030namespace art {
31
David Brazdilc74652862015-05-13 17:50:09 +010032static bool HasWhitespace(const char* str) {
33 DCHECK(str != nullptr);
34 while (str[0] != 0) {
35 if (isspace(str[0])) {
36 return true;
37 }
38 str++;
39 }
40 return false;
41}
42
43class StringList {
44 public:
David Brazdilc7a24852015-05-15 16:44:05 +010045 enum Format {
46 kArrayBrackets,
47 kSetBrackets,
48 };
49
David Brazdilc74652862015-05-13 17:50:09 +010050 // Create an empty list
David Brazdilf1a9ff72015-05-18 16:04:53 +010051 explicit StringList(Format format = kArrayBrackets) : format_(format), is_empty_(true) {}
David Brazdilc74652862015-05-13 17:50:09 +010052
53 // Construct StringList from a linked list. List element class T
54 // must provide methods `GetNext` and `Dump`.
55 template<class T>
David Brazdilc7a24852015-05-15 16:44:05 +010056 explicit StringList(T* first_entry, Format format = kArrayBrackets) : StringList(format) {
David Brazdilc74652862015-05-13 17:50:09 +010057 for (T* current = first_entry; current != nullptr; current = current->GetNext()) {
58 current->Dump(NewEntryStream());
59 }
60 }
61
62 std::ostream& NewEntryStream() {
63 if (is_empty_) {
64 is_empty_ = false;
65 } else {
David Brazdilc57397b2015-05-15 16:01:59 +010066 sstream_ << ",";
David Brazdilc74652862015-05-13 17:50:09 +010067 }
68 return sstream_;
69 }
70
71 private:
David Brazdilc7a24852015-05-15 16:44:05 +010072 Format format_;
David Brazdilc74652862015-05-13 17:50:09 +010073 bool is_empty_;
74 std::ostringstream sstream_;
75
76 friend std::ostream& operator<<(std::ostream& os, const StringList& list);
77};
78
79std::ostream& operator<<(std::ostream& os, const StringList& list) {
David Brazdilc7a24852015-05-15 16:44:05 +010080 switch (list.format_) {
81 case StringList::kArrayBrackets: return os << "[" << list.sstream_.str() << "]";
82 case StringList::kSetBrackets: return os << "{" << list.sstream_.str() << "}";
83 default:
84 LOG(FATAL) << "Invalid StringList format";
85 UNREACHABLE();
86 }
David Brazdilc74652862015-05-13 17:50:09 +010087}
88
Nicolas Geoffrayf635e632014-05-14 09:43:38 +010089/**
90 * HGraph visitor to generate a file suitable for the c1visualizer tool and IRHydra.
91 */
92class HGraphVisualizerPrinter : public HGraphVisitor {
93 public:
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +010094 HGraphVisualizerPrinter(HGraph* graph,
95 std::ostream& output,
96 const char* pass_name,
Nicolas Geoffray840e5462015-01-07 16:01:24 +000097 bool is_after_pass,
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +010098 const CodeGenerator& codegen)
99 : HGraphVisitor(graph),
100 output_(output),
101 pass_name_(pass_name),
Nicolas Geoffray840e5462015-01-07 16:01:24 +0000102 is_after_pass_(is_after_pass),
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100103 codegen_(codegen),
104 indent_(0) {}
Nicolas Geoffrayf635e632014-05-14 09:43:38 +0100105
106 void StartTag(const char* name) {
107 AddIndent();
108 output_ << "begin_" << name << std::endl;
109 indent_++;
110 }
111
112 void EndTag(const char* name) {
113 indent_--;
114 AddIndent();
115 output_ << "end_" << name << std::endl;
116 }
117
118 void PrintProperty(const char* name, const char* property) {
119 AddIndent();
120 output_ << name << " \"" << property << "\"" << std::endl;
121 }
122
123 void PrintProperty(const char* name, const char* property, int id) {
124 AddIndent();
125 output_ << name << " \"" << property << id << "\"" << std::endl;
126 }
127
128 void PrintEmptyProperty(const char* name) {
129 AddIndent();
130 output_ << name << std::endl;
131 }
132
133 void PrintTime(const char* name) {
134 AddIndent();
Jean Christophe Beyler0ada95d2014-12-04 11:20:20 -0800135 output_ << name << " " << time(nullptr) << std::endl;
Nicolas Geoffrayf635e632014-05-14 09:43:38 +0100136 }
137
138 void PrintInt(const char* name, int value) {
139 AddIndent();
140 output_ << name << " " << value << std::endl;
141 }
142
143 void AddIndent() {
144 for (size_t i = 0; i < indent_; ++i) {
145 output_ << " ";
146 }
147 }
148
Nicolas Geoffrayb09aacb2014-09-17 18:21:53 +0100149 char GetTypeId(Primitive::Type type) {
Nicolas Geoffray18efde52014-09-22 15:51:11 +0100150 // Note that Primitive::Descriptor would not work for us
151 // because it does not handle reference types (that is kPrimNot).
Nicolas Geoffrayb09aacb2014-09-17 18:21:53 +0100152 switch (type) {
153 case Primitive::kPrimBoolean: return 'z';
154 case Primitive::kPrimByte: return 'b';
155 case Primitive::kPrimChar: return 'c';
156 case Primitive::kPrimShort: return 's';
157 case Primitive::kPrimInt: return 'i';
158 case Primitive::kPrimLong: return 'j';
159 case Primitive::kPrimFloat: return 'f';
160 case Primitive::kPrimDouble: return 'd';
161 case Primitive::kPrimNot: return 'l';
162 case Primitive::kPrimVoid: return 'v';
163 }
164 LOG(FATAL) << "Unreachable";
165 return 'v';
166 }
167
Nicolas Geoffrayf635e632014-05-14 09:43:38 +0100168 void PrintPredecessors(HBasicBlock* block) {
169 AddIndent();
170 output_ << "predecessors";
171 for (size_t i = 0, e = block->GetPredecessors().Size(); i < e; ++i) {
172 HBasicBlock* predecessor = block->GetPredecessors().Get(i);
173 output_ << " \"B" << predecessor->GetBlockId() << "\" ";
174 }
175 output_<< std::endl;
176 }
177
178 void PrintSuccessors(HBasicBlock* block) {
179 AddIndent();
180 output_ << "successors";
181 for (size_t i = 0, e = block->GetSuccessors().Size(); i < e; ++i) {
182 HBasicBlock* successor = block->GetSuccessors().Get(i);
183 output_ << " \"B" << successor->GetBlockId() << "\" ";
184 }
185 output_<< std::endl;
186 }
187
David Brazdilc74652862015-05-13 17:50:09 +0100188 void DumpLocation(std::ostream& stream, const Location& location) {
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100189 if (location.IsRegister()) {
David Brazdilc74652862015-05-13 17:50:09 +0100190 codegen_.DumpCoreRegister(stream, location.reg());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100191 } else if (location.IsFpuRegister()) {
David Brazdilc74652862015-05-13 17:50:09 +0100192 codegen_.DumpFloatingPointRegister(stream, location.reg());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100193 } else if (location.IsConstant()) {
David Brazdilc74652862015-05-13 17:50:09 +0100194 stream << "#";
Nicolas Geoffray18efde52014-09-22 15:51:11 +0100195 HConstant* constant = location.GetConstant();
196 if (constant->IsIntConstant()) {
David Brazdilc74652862015-05-13 17:50:09 +0100197 stream << constant->AsIntConstant()->GetValue();
Nicolas Geoffray18efde52014-09-22 15:51:11 +0100198 } else if (constant->IsLongConstant()) {
David Brazdilc74652862015-05-13 17:50:09 +0100199 stream << constant->AsLongConstant()->GetValue();
Nicolas Geoffray18efde52014-09-22 15:51:11 +0100200 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100201 } else if (location.IsInvalid()) {
David Brazdilc74652862015-05-13 17:50:09 +0100202 stream << "invalid";
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100203 } else if (location.IsStackSlot()) {
David Brazdilc74652862015-05-13 17:50:09 +0100204 stream << location.GetStackIndex() << "(sp)";
Nicolas Geoffray840e5462015-01-07 16:01:24 +0000205 } else if (location.IsFpuRegisterPair()) {
David Brazdilc74652862015-05-13 17:50:09 +0100206 codegen_.DumpFloatingPointRegister(stream, location.low());
207 stream << "|";
208 codegen_.DumpFloatingPointRegister(stream, location.high());
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +0000209 } else if (location.IsRegisterPair()) {
David Brazdilc74652862015-05-13 17:50:09 +0100210 codegen_.DumpCoreRegister(stream, location.low());
211 stream << "|";
212 codegen_.DumpCoreRegister(stream, location.high());
Mark Mendell09ed1a32015-03-25 08:30:06 -0400213 } else if (location.IsUnallocated()) {
David Brazdilc74652862015-05-13 17:50:09 +0100214 stream << "unallocated";
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100215 } else {
216 DCHECK(location.IsDoubleStackSlot());
David Brazdilc74652862015-05-13 17:50:09 +0100217 stream << "2x" << location.GetStackIndex() << "(sp)";
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100218 }
219 }
220
David Brazdilc74652862015-05-13 17:50:09 +0100221 std::ostream& StartAttributeStream(const char* name = nullptr) {
222 if (name == nullptr) {
223 output_ << " ";
224 } else {
225 DCHECK(!HasWhitespace(name)) << "Checker does not allow spaces in attributes";
226 output_ << " " << name << ":";
227 }
228 return output_;
229 }
230
David Brazdilb7e4a062014-12-29 15:35:02 +0000231 void VisitParallelMove(HParallelMove* instruction) OVERRIDE {
David Brazdilc74652862015-05-13 17:50:09 +0100232 StartAttributeStream("liveness") << instruction->GetLifetimePosition();
233 StringList moves;
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100234 for (size_t i = 0, e = instruction->NumMoves(); i < e; ++i) {
235 MoveOperands* move = instruction->MoveOperandsAt(i);
David Brazdilc74652862015-05-13 17:50:09 +0100236 std::ostream& str = moves.NewEntryStream();
237 DumpLocation(str, move->GetSource());
238 str << "->";
239 DumpLocation(str, move->GetDestination());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100240 }
David Brazdilc74652862015-05-13 17:50:09 +0100241 StartAttributeStream("moves") << moves;
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100242 }
Nicolas Geoffrayf635e632014-05-14 09:43:38 +0100243
David Brazdil36cf0952015-01-08 19:28:33 +0000244 void VisitIntConstant(HIntConstant* instruction) OVERRIDE {
David Brazdilc74652862015-05-13 17:50:09 +0100245 StartAttributeStream() << instruction->GetValue();
David Brazdilb7e4a062014-12-29 15:35:02 +0000246 }
247
David Brazdil36cf0952015-01-08 19:28:33 +0000248 void VisitLongConstant(HLongConstant* instruction) OVERRIDE {
David Brazdilc74652862015-05-13 17:50:09 +0100249 StartAttributeStream() << instruction->GetValue();
David Brazdilb7e4a062014-12-29 15:35:02 +0000250 }
251
David Brazdil36cf0952015-01-08 19:28:33 +0000252 void VisitFloatConstant(HFloatConstant* instruction) OVERRIDE {
David Brazdilc74652862015-05-13 17:50:09 +0100253 StartAttributeStream() << instruction->GetValue();
David Brazdilb7e4a062014-12-29 15:35:02 +0000254 }
255
David Brazdil36cf0952015-01-08 19:28:33 +0000256 void VisitDoubleConstant(HDoubleConstant* instruction) OVERRIDE {
David Brazdilc74652862015-05-13 17:50:09 +0100257 StartAttributeStream() << instruction->GetValue();
David Brazdilb7e4a062014-12-29 15:35:02 +0000258 }
259
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +0000260 void VisitPhi(HPhi* phi) OVERRIDE {
David Brazdilc74652862015-05-13 17:50:09 +0100261 StartAttributeStream("reg") << phi->GetRegNumber();
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +0000262 }
263
Calin Juravle27df7582015-04-17 19:12:31 +0100264 void VisitMemoryBarrier(HMemoryBarrier* barrier) OVERRIDE {
David Brazdilc74652862015-05-13 17:50:09 +0100265 StartAttributeStream("kind") << barrier->GetBarrierKind();
Calin Juravle27df7582015-04-17 19:12:31 +0100266 }
267
Andreas Gampe7c3952f2015-02-19 18:21:24 -0800268 bool IsPass(const char* name) {
269 return strcmp(pass_name_, name) == 0;
270 }
271
David Brazdilb7e4a062014-12-29 15:35:02 +0000272 void PrintInstruction(HInstruction* instruction) {
Nicolas Geoffrayf635e632014-05-14 09:43:38 +0100273 output_ << instruction->DebugName();
274 if (instruction->InputCount() > 0) {
David Brazdilc74652862015-05-13 17:50:09 +0100275 StringList inputs;
276 for (HInputIterator it(instruction); !it.Done(); it.Advance()) {
277 inputs.NewEntryStream() << GetTypeId(it.Current()->GetType()) << it.Current()->GetId();
Nicolas Geoffrayf635e632014-05-14 09:43:38 +0100278 }
David Brazdilc74652862015-05-13 17:50:09 +0100279 StartAttributeStream() << inputs;
Nicolas Geoffrayf635e632014-05-14 09:43:38 +0100280 }
David Brazdilc74652862015-05-13 17:50:09 +0100281 instruction->Accept(this);
Zheng Xubb7a28a2015-01-09 14:40:47 +0800282 if (instruction->HasEnvironment()) {
David Brazdilc74652862015-05-13 17:50:09 +0100283 StringList envs;
Nicolas Geoffray0a23d742015-05-07 11:57:35 +0100284 for (HEnvironment* environment = instruction->GetEnvironment();
285 environment != nullptr;
286 environment = environment->GetParent()) {
David Brazdilc74652862015-05-13 17:50:09 +0100287 StringList vregs;
Nicolas Geoffray0a23d742015-05-07 11:57:35 +0100288 for (size_t i = 0, e = environment->Size(); i < e; ++i) {
289 HInstruction* insn = environment->GetInstructionAt(i);
290 if (insn != nullptr) {
David Brazdilc74652862015-05-13 17:50:09 +0100291 vregs.NewEntryStream() << GetTypeId(insn->GetType()) << insn->GetId();
Nicolas Geoffray0a23d742015-05-07 11:57:35 +0100292 } else {
David Brazdilc74652862015-05-13 17:50:09 +0100293 vregs.NewEntryStream() << "_";
Nicolas Geoffray0a23d742015-05-07 11:57:35 +0100294 }
Zheng Xubb7a28a2015-01-09 14:40:47 +0800295 }
David Brazdilc74652862015-05-13 17:50:09 +0100296 envs.NewEntryStream() << vregs;
Zheng Xubb7a28a2015-01-09 14:40:47 +0800297 }
David Brazdilc74652862015-05-13 17:50:09 +0100298 StartAttributeStream("env") << envs;
Zheng Xubb7a28a2015-01-09 14:40:47 +0800299 }
Andreas Gampe7c3952f2015-02-19 18:21:24 -0800300 if (IsPass(SsaLivenessAnalysis::kLivenessPassName)
David Brazdil5e8b1372015-01-23 14:39:08 +0000301 && is_after_pass_
302 && instruction->GetLifetimePosition() != kNoLifetime) {
David Brazdilc74652862015-05-13 17:50:09 +0100303 StartAttributeStream("liveness") << instruction->GetLifetimePosition();
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100304 if (instruction->HasLiveInterval()) {
David Brazdilc74652862015-05-13 17:50:09 +0100305 LiveInterval* interval = instruction->GetLiveInterval();
David Brazdilc7a24852015-05-15 16:44:05 +0100306 StartAttributeStream("ranges")
307 << StringList(interval->GetFirstRange(), StringList::kSetBrackets);
David Brazdilc74652862015-05-13 17:50:09 +0100308 StartAttributeStream("uses") << StringList(interval->GetFirstUse());
309 StartAttributeStream("env_uses") << StringList(interval->GetFirstEnvironmentUse());
310 StartAttributeStream("is_fixed") << interval->IsFixed();
311 StartAttributeStream("is_split") << interval->IsSplit();
312 StartAttributeStream("is_low") << interval->IsLowInterval();
313 StartAttributeStream("is_high") << interval->IsHighInterval();
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100314 }
Andreas Gampe7c3952f2015-02-19 18:21:24 -0800315 } else if (IsPass(RegisterAllocator::kRegisterAllocatorPassName) && is_after_pass_) {
David Brazdilc74652862015-05-13 17:50:09 +0100316 StartAttributeStream("liveness") << instruction->GetLifetimePosition();
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100317 LocationSummary* locations = instruction->GetLocations();
318 if (locations != nullptr) {
David Brazdilc74652862015-05-13 17:50:09 +0100319 StringList inputs;
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100320 for (size_t i = 0; i < instruction->InputCount(); ++i) {
David Brazdilc74652862015-05-13 17:50:09 +0100321 DumpLocation(inputs.NewEntryStream(), locations->InAt(i));
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100322 }
David Brazdilc74652862015-05-13 17:50:09 +0100323 std::ostream& attr = StartAttributeStream("locations");
324 attr << inputs << "->";
325 DumpLocation(attr, locations->Out());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100326 }
David Brazdila4b8c212015-05-07 09:59:30 +0100327 } else if (IsPass(LICM::kLoopInvariantCodeMotionPassName)
328 || IsPass(HDeadCodeElimination::kFinalDeadCodeEliminationPassName)) {
Nicolas Geoffray82091da2015-01-26 10:02:45 +0000329 HLoopInformation* info = instruction->GetBlock()->GetLoopInformation();
330 if (info == nullptr) {
David Brazdilc74652862015-05-13 17:50:09 +0100331 StartAttributeStream("loop") << "none";
Nicolas Geoffray82091da2015-01-26 10:02:45 +0000332 } else {
David Brazdilc74652862015-05-13 17:50:09 +0100333 StartAttributeStream("loop") << "B" << info->GetHeader()->GetBlockId();
Nicolas Geoffray82091da2015-01-26 10:02:45 +0000334 }
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100335 }
Nicolas Geoffrayf635e632014-05-14 09:43:38 +0100336 }
337
338 void PrintInstructions(const HInstructionList& list) {
339 const char* kEndInstructionMarker = "<|@";
340 for (HInstructionIterator it(list); !it.Done(); it.Advance()) {
341 HInstruction* instruction = it.Current();
Nicolas Geoffrayf635e632014-05-14 09:43:38 +0100342 int bci = 0;
David Brazdilea55b932015-01-27 17:12:29 +0000343 size_t num_uses = 0;
344 for (HUseIterator<HInstruction*> use_it(instruction->GetUses());
345 !use_it.Done();
346 use_it.Advance()) {
347 ++num_uses;
348 }
349 AddIndent();
350 output_ << bci << " " << num_uses << " "
351 << GetTypeId(instruction->GetType()) << instruction->GetId() << " ";
David Brazdilb7e4a062014-12-29 15:35:02 +0000352 PrintInstruction(instruction);
David Brazdilc74652862015-05-13 17:50:09 +0100353 output_ << " " << kEndInstructionMarker << std::endl;
Nicolas Geoffrayf635e632014-05-14 09:43:38 +0100354 }
355 }
356
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100357 void Run() {
Nicolas Geoffrayf635e632014-05-14 09:43:38 +0100358 StartTag("cfg");
Nicolas Geoffray840e5462015-01-07 16:01:24 +0000359 std::string pass_desc = std::string(pass_name_) + (is_after_pass_ ? " (after)" : " (before)");
360 PrintProperty("name", pass_desc.c_str());
Nicolas Geoffrayf635e632014-05-14 09:43:38 +0100361 VisitInsertionOrder();
362 EndTag("cfg");
363 }
364
David Brazdilb7e4a062014-12-29 15:35:02 +0000365 void VisitBasicBlock(HBasicBlock* block) OVERRIDE {
Nicolas Geoffrayf635e632014-05-14 09:43:38 +0100366 StartTag("block");
367 PrintProperty("name", "B", block->GetBlockId());
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100368 if (block->GetLifetimeStart() != kNoLifetime) {
369 // Piggy back on these fields to show the lifetime of the block.
370 PrintInt("from_bci", block->GetLifetimeStart());
371 PrintInt("to_bci", block->GetLifetimeEnd());
372 } else {
373 PrintInt("from_bci", -1);
374 PrintInt("to_bci", -1);
375 }
Nicolas Geoffrayf635e632014-05-14 09:43:38 +0100376 PrintPredecessors(block);
377 PrintSuccessors(block);
378 PrintEmptyProperty("xhandlers");
379 PrintEmptyProperty("flags");
380 if (block->GetDominator() != nullptr) {
381 PrintProperty("dominator", "B", block->GetDominator()->GetBlockId());
382 }
383
384 StartTag("states");
385 StartTag("locals");
386 PrintInt("size", 0);
387 PrintProperty("method", "None");
388 for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
389 AddIndent();
390 HInstruction* instruction = it.Current();
Nicolas Geoffrayb09aacb2014-09-17 18:21:53 +0100391 output_ << instruction->GetId() << " " << GetTypeId(instruction->GetType())
392 << instruction->GetId() << "[ ";
Nicolas Geoffrayf635e632014-05-14 09:43:38 +0100393 for (HInputIterator inputs(instruction); !inputs.Done(); inputs.Advance()) {
394 output_ << inputs.Current()->GetId() << " ";
395 }
396 output_ << "]" << std::endl;
397 }
398 EndTag("locals");
399 EndTag("states");
400
401 StartTag("HIR");
402 PrintInstructions(block->GetPhis());
403 PrintInstructions(block->GetInstructions());
404 EndTag("HIR");
405 EndTag("block");
406 }
407
408 private:
409 std::ostream& output_;
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100410 const char* pass_name_;
Nicolas Geoffray840e5462015-01-07 16:01:24 +0000411 const bool is_after_pass_;
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100412 const CodeGenerator& codegen_;
Nicolas Geoffrayf635e632014-05-14 09:43:38 +0100413 size_t indent_;
414
415 DISALLOW_COPY_AND_ASSIGN(HGraphVisualizerPrinter);
416};
417
418HGraphVisualizer::HGraphVisualizer(std::ostream* output,
419 HGraph* graph,
David Brazdil62e074f2015-04-07 18:09:37 +0100420 const CodeGenerator& codegen)
421 : output_(output), graph_(graph), codegen_(codegen) {}
Nicolas Geoffrayf635e632014-05-14 09:43:38 +0100422
David Brazdil62e074f2015-04-07 18:09:37 +0100423void HGraphVisualizer::PrintHeader(const char* method_name) const {
424 DCHECK(output_ != nullptr);
Nicolas Geoffray840e5462015-01-07 16:01:24 +0000425 HGraphVisualizerPrinter printer(graph_, *output_, "", true, codegen_);
Nicolas Geoffrayf635e632014-05-14 09:43:38 +0100426 printer.StartTag("compilation");
Nicolas Geoffraye53798a2014-12-01 10:31:54 +0000427 printer.PrintProperty("name", method_name);
428 printer.PrintProperty("method", method_name);
Nicolas Geoffray0d3f5782014-05-14 09:43:38 +0100429 printer.PrintTime("date");
430 printer.EndTag("compilation");
431}
432
David Brazdilee690a32014-12-01 17:04:16 +0000433void HGraphVisualizer::DumpGraph(const char* pass_name, bool is_after_pass) const {
David Brazdil5e8b1372015-01-23 14:39:08 +0000434 DCHECK(output_ != nullptr);
435 if (!graph_->GetBlocks().IsEmpty()) {
Nicolas Geoffray840e5462015-01-07 16:01:24 +0000436 HGraphVisualizerPrinter printer(graph_, *output_, pass_name, is_after_pass, codegen_);
David Brazdilee690a32014-12-01 17:04:16 +0000437 printer.Run();
Nicolas Geoffrayf635e632014-05-14 09:43:38 +0100438 }
Nicolas Geoffrayf635e632014-05-14 09:43:38 +0100439}
440
441} // namespace art