blob: 7da4f2d1fd58fbe9792f5ca883c4ca6e5b18f8b6 [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
Calin Juravle0ba218d2015-05-19 18:46:01 +0100268 void VisitLoadClass(HLoadClass* load_cass) OVERRIDE {
269 StartAttributeStream("gen_clinit_check") << std::boolalpha
270 << load_cass->MustGenerateClinitCheck() << std::noboolalpha;
271 }
272
Guillaume "Vermeille" Sanchez9099ef72015-05-20 15:19:21 +0100273 void VisitCheckCast(HCheckCast* check_cast) OVERRIDE {
274 StartAttributeStream("must_do_null_check") << std::boolalpha
275 << check_cast->MustDoNullCheck() << std::noboolalpha;
276 }
277
278 void VisitInstanceOf(HInstanceOf* instance_of) OVERRIDE {
279 StartAttributeStream("must_do_null_check") << std::boolalpha
280 << instance_of->MustDoNullCheck() << std::noboolalpha;
281 }
282
Andreas Gampe7c3952f2015-02-19 18:21:24 -0800283 bool IsPass(const char* name) {
284 return strcmp(pass_name_, name) == 0;
285 }
286
David Brazdilb7e4a062014-12-29 15:35:02 +0000287 void PrintInstruction(HInstruction* instruction) {
Nicolas Geoffrayf635e632014-05-14 09:43:38 +0100288 output_ << instruction->DebugName();
289 if (instruction->InputCount() > 0) {
David Brazdilc74652862015-05-13 17:50:09 +0100290 StringList inputs;
291 for (HInputIterator it(instruction); !it.Done(); it.Advance()) {
292 inputs.NewEntryStream() << GetTypeId(it.Current()->GetType()) << it.Current()->GetId();
Nicolas Geoffrayf635e632014-05-14 09:43:38 +0100293 }
David Brazdilc74652862015-05-13 17:50:09 +0100294 StartAttributeStream() << inputs;
Nicolas Geoffrayf635e632014-05-14 09:43:38 +0100295 }
David Brazdilc74652862015-05-13 17:50:09 +0100296 instruction->Accept(this);
Zheng Xubb7a28a2015-01-09 14:40:47 +0800297 if (instruction->HasEnvironment()) {
David Brazdilc74652862015-05-13 17:50:09 +0100298 StringList envs;
Nicolas Geoffray0a23d742015-05-07 11:57:35 +0100299 for (HEnvironment* environment = instruction->GetEnvironment();
300 environment != nullptr;
301 environment = environment->GetParent()) {
David Brazdilc74652862015-05-13 17:50:09 +0100302 StringList vregs;
Nicolas Geoffray0a23d742015-05-07 11:57:35 +0100303 for (size_t i = 0, e = environment->Size(); i < e; ++i) {
304 HInstruction* insn = environment->GetInstructionAt(i);
305 if (insn != nullptr) {
David Brazdilc74652862015-05-13 17:50:09 +0100306 vregs.NewEntryStream() << GetTypeId(insn->GetType()) << insn->GetId();
Nicolas Geoffray0a23d742015-05-07 11:57:35 +0100307 } else {
David Brazdilc74652862015-05-13 17:50:09 +0100308 vregs.NewEntryStream() << "_";
Nicolas Geoffray0a23d742015-05-07 11:57:35 +0100309 }
Zheng Xubb7a28a2015-01-09 14:40:47 +0800310 }
David Brazdilc74652862015-05-13 17:50:09 +0100311 envs.NewEntryStream() << vregs;
Zheng Xubb7a28a2015-01-09 14:40:47 +0800312 }
David Brazdilc74652862015-05-13 17:50:09 +0100313 StartAttributeStream("env") << envs;
Zheng Xubb7a28a2015-01-09 14:40:47 +0800314 }
Andreas Gampe7c3952f2015-02-19 18:21:24 -0800315 if (IsPass(SsaLivenessAnalysis::kLivenessPassName)
David Brazdil5e8b1372015-01-23 14:39:08 +0000316 && is_after_pass_
317 && instruction->GetLifetimePosition() != kNoLifetime) {
David Brazdilc74652862015-05-13 17:50:09 +0100318 StartAttributeStream("liveness") << instruction->GetLifetimePosition();
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100319 if (instruction->HasLiveInterval()) {
David Brazdilc74652862015-05-13 17:50:09 +0100320 LiveInterval* interval = instruction->GetLiveInterval();
David Brazdilc7a24852015-05-15 16:44:05 +0100321 StartAttributeStream("ranges")
322 << StringList(interval->GetFirstRange(), StringList::kSetBrackets);
David Brazdilc74652862015-05-13 17:50:09 +0100323 StartAttributeStream("uses") << StringList(interval->GetFirstUse());
324 StartAttributeStream("env_uses") << StringList(interval->GetFirstEnvironmentUse());
325 StartAttributeStream("is_fixed") << interval->IsFixed();
326 StartAttributeStream("is_split") << interval->IsSplit();
327 StartAttributeStream("is_low") << interval->IsLowInterval();
328 StartAttributeStream("is_high") << interval->IsHighInterval();
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100329 }
Andreas Gampe7c3952f2015-02-19 18:21:24 -0800330 } else if (IsPass(RegisterAllocator::kRegisterAllocatorPassName) && is_after_pass_) {
David Brazdilc74652862015-05-13 17:50:09 +0100331 StartAttributeStream("liveness") << instruction->GetLifetimePosition();
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100332 LocationSummary* locations = instruction->GetLocations();
333 if (locations != nullptr) {
David Brazdilc74652862015-05-13 17:50:09 +0100334 StringList inputs;
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100335 for (size_t i = 0; i < instruction->InputCount(); ++i) {
David Brazdilc74652862015-05-13 17:50:09 +0100336 DumpLocation(inputs.NewEntryStream(), locations->InAt(i));
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100337 }
David Brazdilc74652862015-05-13 17:50:09 +0100338 std::ostream& attr = StartAttributeStream("locations");
339 attr << inputs << "->";
340 DumpLocation(attr, locations->Out());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100341 }
David Brazdila4b8c212015-05-07 09:59:30 +0100342 } else if (IsPass(LICM::kLoopInvariantCodeMotionPassName)
343 || IsPass(HDeadCodeElimination::kFinalDeadCodeEliminationPassName)) {
Nicolas Geoffray82091da2015-01-26 10:02:45 +0000344 HLoopInformation* info = instruction->GetBlock()->GetLoopInformation();
345 if (info == nullptr) {
David Brazdilc74652862015-05-13 17:50:09 +0100346 StartAttributeStream("loop") << "none";
Nicolas Geoffray82091da2015-01-26 10:02:45 +0000347 } else {
David Brazdilc74652862015-05-13 17:50:09 +0100348 StartAttributeStream("loop") << "B" << info->GetHeader()->GetBlockId();
Nicolas Geoffray82091da2015-01-26 10:02:45 +0000349 }
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100350 }
Nicolas Geoffrayf635e632014-05-14 09:43:38 +0100351 }
352
353 void PrintInstructions(const HInstructionList& list) {
354 const char* kEndInstructionMarker = "<|@";
355 for (HInstructionIterator it(list); !it.Done(); it.Advance()) {
356 HInstruction* instruction = it.Current();
Nicolas Geoffrayf635e632014-05-14 09:43:38 +0100357 int bci = 0;
David Brazdilea55b932015-01-27 17:12:29 +0000358 size_t num_uses = 0;
359 for (HUseIterator<HInstruction*> use_it(instruction->GetUses());
360 !use_it.Done();
361 use_it.Advance()) {
362 ++num_uses;
363 }
364 AddIndent();
365 output_ << bci << " " << num_uses << " "
366 << GetTypeId(instruction->GetType()) << instruction->GetId() << " ";
David Brazdilb7e4a062014-12-29 15:35:02 +0000367 PrintInstruction(instruction);
David Brazdilc74652862015-05-13 17:50:09 +0100368 output_ << " " << kEndInstructionMarker << std::endl;
Nicolas Geoffrayf635e632014-05-14 09:43:38 +0100369 }
370 }
371
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100372 void Run() {
Nicolas Geoffrayf635e632014-05-14 09:43:38 +0100373 StartTag("cfg");
Nicolas Geoffray840e5462015-01-07 16:01:24 +0000374 std::string pass_desc = std::string(pass_name_) + (is_after_pass_ ? " (after)" : " (before)");
375 PrintProperty("name", pass_desc.c_str());
Nicolas Geoffrayf635e632014-05-14 09:43:38 +0100376 VisitInsertionOrder();
377 EndTag("cfg");
378 }
379
David Brazdilb7e4a062014-12-29 15:35:02 +0000380 void VisitBasicBlock(HBasicBlock* block) OVERRIDE {
Nicolas Geoffrayf635e632014-05-14 09:43:38 +0100381 StartTag("block");
382 PrintProperty("name", "B", block->GetBlockId());
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100383 if (block->GetLifetimeStart() != kNoLifetime) {
384 // Piggy back on these fields to show the lifetime of the block.
385 PrintInt("from_bci", block->GetLifetimeStart());
386 PrintInt("to_bci", block->GetLifetimeEnd());
387 } else {
388 PrintInt("from_bci", -1);
389 PrintInt("to_bci", -1);
390 }
Nicolas Geoffrayf635e632014-05-14 09:43:38 +0100391 PrintPredecessors(block);
392 PrintSuccessors(block);
393 PrintEmptyProperty("xhandlers");
394 PrintEmptyProperty("flags");
395 if (block->GetDominator() != nullptr) {
396 PrintProperty("dominator", "B", block->GetDominator()->GetBlockId());
397 }
398
399 StartTag("states");
400 StartTag("locals");
401 PrintInt("size", 0);
402 PrintProperty("method", "None");
403 for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
404 AddIndent();
405 HInstruction* instruction = it.Current();
Nicolas Geoffrayb09aacb2014-09-17 18:21:53 +0100406 output_ << instruction->GetId() << " " << GetTypeId(instruction->GetType())
407 << instruction->GetId() << "[ ";
Nicolas Geoffrayf635e632014-05-14 09:43:38 +0100408 for (HInputIterator inputs(instruction); !inputs.Done(); inputs.Advance()) {
409 output_ << inputs.Current()->GetId() << " ";
410 }
411 output_ << "]" << std::endl;
412 }
413 EndTag("locals");
414 EndTag("states");
415
416 StartTag("HIR");
417 PrintInstructions(block->GetPhis());
418 PrintInstructions(block->GetInstructions());
419 EndTag("HIR");
420 EndTag("block");
421 }
422
423 private:
424 std::ostream& output_;
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100425 const char* pass_name_;
Nicolas Geoffray840e5462015-01-07 16:01:24 +0000426 const bool is_after_pass_;
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100427 const CodeGenerator& codegen_;
Nicolas Geoffrayf635e632014-05-14 09:43:38 +0100428 size_t indent_;
429
430 DISALLOW_COPY_AND_ASSIGN(HGraphVisualizerPrinter);
431};
432
433HGraphVisualizer::HGraphVisualizer(std::ostream* output,
434 HGraph* graph,
David Brazdil62e074f2015-04-07 18:09:37 +0100435 const CodeGenerator& codegen)
436 : output_(output), graph_(graph), codegen_(codegen) {}
Nicolas Geoffrayf635e632014-05-14 09:43:38 +0100437
David Brazdil62e074f2015-04-07 18:09:37 +0100438void HGraphVisualizer::PrintHeader(const char* method_name) const {
439 DCHECK(output_ != nullptr);
Nicolas Geoffray840e5462015-01-07 16:01:24 +0000440 HGraphVisualizerPrinter printer(graph_, *output_, "", true, codegen_);
Nicolas Geoffrayf635e632014-05-14 09:43:38 +0100441 printer.StartTag("compilation");
Nicolas Geoffraye53798a2014-12-01 10:31:54 +0000442 printer.PrintProperty("name", method_name);
443 printer.PrintProperty("method", method_name);
Nicolas Geoffray0d3f5782014-05-14 09:43:38 +0100444 printer.PrintTime("date");
445 printer.EndTag("compilation");
446}
447
David Brazdilee690a32014-12-01 17:04:16 +0000448void HGraphVisualizer::DumpGraph(const char* pass_name, bool is_after_pass) const {
David Brazdil5e8b1372015-01-23 14:39:08 +0000449 DCHECK(output_ != nullptr);
450 if (!graph_->GetBlocks().IsEmpty()) {
Nicolas Geoffray840e5462015-01-07 16:01:24 +0000451 HGraphVisualizerPrinter printer(graph_, *output_, pass_name, is_after_pass, codegen_);
David Brazdilee690a32014-12-01 17:04:16 +0000452 printer.Run();
Nicolas Geoffrayf635e632014-05-14 09:43:38 +0100453 }
Nicolas Geoffrayf635e632014-05-14 09:43:38 +0100454}
455
456} // namespace art