blob: f5c630bf9781166ba11ee902a70155ac5877f503 [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 Brazdile8ff50d2015-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
27namespace art {
28
29/**
30 * HGraph visitor to generate a file suitable for the c1visualizer tool and IRHydra.
31 */
32class HGraphVisualizerPrinter : public HGraphVisitor {
33 public:
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +010034 HGraphVisualizerPrinter(HGraph* graph,
35 std::ostream& output,
36 const char* pass_name,
Nicolas Geoffray840e5462015-01-07 16:01:24 +000037 bool is_after_pass,
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +010038 const CodeGenerator& codegen)
39 : HGraphVisitor(graph),
40 output_(output),
41 pass_name_(pass_name),
Nicolas Geoffray840e5462015-01-07 16:01:24 +000042 is_after_pass_(is_after_pass),
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +010043 codegen_(codegen),
44 indent_(0) {}
Nicolas Geoffrayf635e632014-05-14 09:43:38 +010045
46 void StartTag(const char* name) {
47 AddIndent();
48 output_ << "begin_" << name << std::endl;
49 indent_++;
50 }
51
52 void EndTag(const char* name) {
53 indent_--;
54 AddIndent();
55 output_ << "end_" << name << std::endl;
56 }
57
58 void PrintProperty(const char* name, const char* property) {
59 AddIndent();
60 output_ << name << " \"" << property << "\"" << std::endl;
61 }
62
63 void PrintProperty(const char* name, const char* property, int id) {
64 AddIndent();
65 output_ << name << " \"" << property << id << "\"" << std::endl;
66 }
67
68 void PrintEmptyProperty(const char* name) {
69 AddIndent();
70 output_ << name << std::endl;
71 }
72
73 void PrintTime(const char* name) {
74 AddIndent();
Jean Christophe Beyler0ada95d2014-12-04 11:20:20 -080075 output_ << name << " " << time(nullptr) << std::endl;
Nicolas Geoffrayf635e632014-05-14 09:43:38 +010076 }
77
78 void PrintInt(const char* name, int value) {
79 AddIndent();
80 output_ << name << " " << value << std::endl;
81 }
82
83 void AddIndent() {
84 for (size_t i = 0; i < indent_; ++i) {
85 output_ << " ";
86 }
87 }
88
Nicolas Geoffrayb09aacb2014-09-17 18:21:53 +010089 char GetTypeId(Primitive::Type type) {
Nicolas Geoffray18efde52014-09-22 15:51:11 +010090 // Note that Primitive::Descriptor would not work for us
91 // because it does not handle reference types (that is kPrimNot).
Nicolas Geoffrayb09aacb2014-09-17 18:21:53 +010092 switch (type) {
93 case Primitive::kPrimBoolean: return 'z';
94 case Primitive::kPrimByte: return 'b';
95 case Primitive::kPrimChar: return 'c';
96 case Primitive::kPrimShort: return 's';
97 case Primitive::kPrimInt: return 'i';
98 case Primitive::kPrimLong: return 'j';
99 case Primitive::kPrimFloat: return 'f';
100 case Primitive::kPrimDouble: return 'd';
101 case Primitive::kPrimNot: return 'l';
102 case Primitive::kPrimVoid: return 'v';
103 }
104 LOG(FATAL) << "Unreachable";
105 return 'v';
106 }
107
Nicolas Geoffrayf635e632014-05-14 09:43:38 +0100108 void PrintPredecessors(HBasicBlock* block) {
109 AddIndent();
110 output_ << "predecessors";
111 for (size_t i = 0, e = block->GetPredecessors().Size(); i < e; ++i) {
112 HBasicBlock* predecessor = block->GetPredecessors().Get(i);
113 output_ << " \"B" << predecessor->GetBlockId() << "\" ";
114 }
115 output_<< std::endl;
116 }
117
118 void PrintSuccessors(HBasicBlock* block) {
119 AddIndent();
120 output_ << "successors";
121 for (size_t i = 0, e = block->GetSuccessors().Size(); i < e; ++i) {
122 HBasicBlock* successor = block->GetSuccessors().Get(i);
123 output_ << " \"B" << successor->GetBlockId() << "\" ";
124 }
125 output_<< std::endl;
126 }
127
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100128 void DumpLocation(Location location) {
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100129 if (location.IsRegister()) {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100130 codegen_.DumpCoreRegister(output_, location.reg());
131 } else if (location.IsFpuRegister()) {
132 codegen_.DumpFloatingPointRegister(output_, location.reg());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100133 } else if (location.IsConstant()) {
134 output_ << "constant";
Nicolas Geoffray18efde52014-09-22 15:51:11 +0100135 HConstant* constant = location.GetConstant();
136 if (constant->IsIntConstant()) {
137 output_ << " " << constant->AsIntConstant()->GetValue();
138 } else if (constant->IsLongConstant()) {
139 output_ << " " << constant->AsLongConstant()->GetValue();
140 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100141 } else if (location.IsInvalid()) {
142 output_ << "invalid";
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100143 } else if (location.IsStackSlot()) {
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100144 output_ << location.GetStackIndex() << "(sp)";
Nicolas Geoffray840e5462015-01-07 16:01:24 +0000145 } else if (location.IsFpuRegisterPair()) {
146 codegen_.DumpFloatingPointRegister(output_, location.low());
147 output_ << " and ";
148 codegen_.DumpFloatingPointRegister(output_, location.high());
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +0000149 } else if (location.IsRegisterPair()) {
150 codegen_.DumpCoreRegister(output_, location.low());
151 output_ << " and ";
152 codegen_.DumpCoreRegister(output_, location.high());
Mark Mendell09ed1a32015-03-25 08:30:06 -0400153 } else if (location.IsUnallocated()) {
154 output_ << "<U>";
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100155 } else {
156 DCHECK(location.IsDoubleStackSlot());
157 output_ << "2x" << location.GetStackIndex() << "(sp)";
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100158 }
159 }
160
David Brazdilb7e4a062014-12-29 15:35:02 +0000161 void VisitParallelMove(HParallelMove* instruction) OVERRIDE {
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100162 output_ << " (";
163 for (size_t i = 0, e = instruction->NumMoves(); i < e; ++i) {
164 MoveOperands* move = instruction->MoveOperandsAt(i);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100165 DumpLocation(move->GetSource());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100166 output_ << " -> ";
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100167 DumpLocation(move->GetDestination());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100168 if (i + 1 != e) {
169 output_ << ", ";
170 }
171 }
172 output_ << ")";
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +0100173 output_ << " (liveness: " << instruction->GetLifetimePosition() << ")";
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100174 }
Nicolas Geoffrayf635e632014-05-14 09:43:38 +0100175
David Brazdil36cf0952015-01-08 19:28:33 +0000176 void VisitIntConstant(HIntConstant* instruction) OVERRIDE {
David Brazdilb7e4a062014-12-29 15:35:02 +0000177 output_ << " " << instruction->GetValue();
178 }
179
David Brazdil36cf0952015-01-08 19:28:33 +0000180 void VisitLongConstant(HLongConstant* instruction) OVERRIDE {
David Brazdilb7e4a062014-12-29 15:35:02 +0000181 output_ << " " << instruction->GetValue();
182 }
183
David Brazdil36cf0952015-01-08 19:28:33 +0000184 void VisitFloatConstant(HFloatConstant* instruction) OVERRIDE {
David Brazdilb7e4a062014-12-29 15:35:02 +0000185 output_ << " " << instruction->GetValue();
186 }
187
David Brazdil36cf0952015-01-08 19:28:33 +0000188 void VisitDoubleConstant(HDoubleConstant* instruction) OVERRIDE {
David Brazdilb7e4a062014-12-29 15:35:02 +0000189 output_ << " " << instruction->GetValue();
190 }
191
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +0000192 void VisitPhi(HPhi* phi) OVERRIDE {
193 output_ << " " << phi->GetRegNumber();
194 }
195
Calin Juravle27df7582015-04-17 19:12:31 +0100196 void VisitMemoryBarrier(HMemoryBarrier* barrier) OVERRIDE {
197 output_ << " " << barrier->GetBarrierKind();
198 }
199
Andreas Gampe7c3952f2015-02-19 18:21:24 -0800200 bool IsPass(const char* name) {
201 return strcmp(pass_name_, name) == 0;
202 }
203
David Brazdilb7e4a062014-12-29 15:35:02 +0000204 void PrintInstruction(HInstruction* instruction) {
Nicolas Geoffrayf635e632014-05-14 09:43:38 +0100205 output_ << instruction->DebugName();
David Brazdilb7e4a062014-12-29 15:35:02 +0000206 instruction->Accept(this);
Nicolas Geoffrayf635e632014-05-14 09:43:38 +0100207 if (instruction->InputCount() > 0) {
208 output_ << " [ ";
209 for (HInputIterator inputs(instruction); !inputs.Done(); inputs.Advance()) {
Nicolas Geoffrayb09aacb2014-09-17 18:21:53 +0100210 output_ << GetTypeId(inputs.Current()->GetType()) << inputs.Current()->GetId() << " ";
Nicolas Geoffrayf635e632014-05-14 09:43:38 +0100211 }
212 output_ << "]";
213 }
Zheng Xubb7a28a2015-01-09 14:40:47 +0800214 if (instruction->HasEnvironment()) {
Nicolas Geoffray0a23d742015-05-07 11:57:35 +0100215 output_ << " (env:";
216 for (HEnvironment* environment = instruction->GetEnvironment();
217 environment != nullptr;
218 environment = environment->GetParent()) {
219 output_ << " [ ";
220 for (size_t i = 0, e = environment->Size(); i < e; ++i) {
221 HInstruction* insn = environment->GetInstructionAt(i);
222 if (insn != nullptr) {
223 output_ << GetTypeId(insn->GetType()) << insn->GetId() << " ";
224 } else {
225 output_ << " _ ";
226 }
Zheng Xubb7a28a2015-01-09 14:40:47 +0800227 }
Nicolas Geoffray0a23d742015-05-07 11:57:35 +0100228 output_ << "]";
Zheng Xubb7a28a2015-01-09 14:40:47 +0800229 }
Nicolas Geoffray0a23d742015-05-07 11:57:35 +0100230 output_ << ")";
Zheng Xubb7a28a2015-01-09 14:40:47 +0800231 }
Andreas Gampe7c3952f2015-02-19 18:21:24 -0800232 if (IsPass(SsaLivenessAnalysis::kLivenessPassName)
David Brazdil5e8b1372015-01-23 14:39:08 +0000233 && is_after_pass_
234 && instruction->GetLifetimePosition() != kNoLifetime) {
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100235 output_ << " (liveness: " << instruction->GetLifetimePosition();
236 if (instruction->HasLiveInterval()) {
237 output_ << " ";
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100238 const LiveInterval& interval = *instruction->GetLiveInterval();
239 interval.Dump(output_);
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100240 }
241 output_ << ")";
Andreas Gampe7c3952f2015-02-19 18:21:24 -0800242 } else if (IsPass(RegisterAllocator::kRegisterAllocatorPassName) && is_after_pass_) {
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100243 LocationSummary* locations = instruction->GetLocations();
244 if (locations != nullptr) {
245 output_ << " ( ";
246 for (size_t i = 0; i < instruction->InputCount(); ++i) {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100247 DumpLocation(locations->InAt(i));
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100248 output_ << " ";
249 }
250 output_ << ")";
251 if (locations->Out().IsValid()) {
252 output_ << " -> ";
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100253 DumpLocation(locations->Out());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100254 }
255 }
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +0100256 output_ << " (liveness: " << instruction->GetLifetimePosition() << ")";
David Brazdile8ff50d2015-05-07 09:59:30 +0100257 } else if (IsPass(LICM::kLoopInvariantCodeMotionPassName)
258 || IsPass(HDeadCodeElimination::kFinalDeadCodeEliminationPassName)) {
Nicolas Geoffray82091da2015-01-26 10:02:45 +0000259 output_ << " ( loop_header:";
260 HLoopInformation* info = instruction->GetBlock()->GetLoopInformation();
261 if (info == nullptr) {
262 output_ << "null )";
263 } else {
264 output_ << "B" << info->GetHeader()->GetBlockId() << " )";
265 }
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100266 }
Nicolas Geoffrayf635e632014-05-14 09:43:38 +0100267 }
268
269 void PrintInstructions(const HInstructionList& list) {
270 const char* kEndInstructionMarker = "<|@";
271 for (HInstructionIterator it(list); !it.Done(); it.Advance()) {
272 HInstruction* instruction = it.Current();
Nicolas Geoffrayf635e632014-05-14 09:43:38 +0100273 int bci = 0;
David Brazdilea55b932015-01-27 17:12:29 +0000274 size_t num_uses = 0;
275 for (HUseIterator<HInstruction*> use_it(instruction->GetUses());
276 !use_it.Done();
277 use_it.Advance()) {
278 ++num_uses;
279 }
280 AddIndent();
281 output_ << bci << " " << num_uses << " "
282 << GetTypeId(instruction->GetType()) << instruction->GetId() << " ";
David Brazdilb7e4a062014-12-29 15:35:02 +0000283 PrintInstruction(instruction);
Nicolas Geoffrayf635e632014-05-14 09:43:38 +0100284 output_ << kEndInstructionMarker << std::endl;
285 }
286 }
287
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100288 void Run() {
Nicolas Geoffrayf635e632014-05-14 09:43:38 +0100289 StartTag("cfg");
Nicolas Geoffray840e5462015-01-07 16:01:24 +0000290 std::string pass_desc = std::string(pass_name_) + (is_after_pass_ ? " (after)" : " (before)");
291 PrintProperty("name", pass_desc.c_str());
Nicolas Geoffrayf635e632014-05-14 09:43:38 +0100292 VisitInsertionOrder();
293 EndTag("cfg");
294 }
295
David Brazdilb7e4a062014-12-29 15:35:02 +0000296 void VisitBasicBlock(HBasicBlock* block) OVERRIDE {
Nicolas Geoffrayf635e632014-05-14 09:43:38 +0100297 StartTag("block");
298 PrintProperty("name", "B", block->GetBlockId());
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100299 if (block->GetLifetimeStart() != kNoLifetime) {
300 // Piggy back on these fields to show the lifetime of the block.
301 PrintInt("from_bci", block->GetLifetimeStart());
302 PrintInt("to_bci", block->GetLifetimeEnd());
303 } else {
304 PrintInt("from_bci", -1);
305 PrintInt("to_bci", -1);
306 }
Nicolas Geoffrayf635e632014-05-14 09:43:38 +0100307 PrintPredecessors(block);
308 PrintSuccessors(block);
309 PrintEmptyProperty("xhandlers");
310 PrintEmptyProperty("flags");
311 if (block->GetDominator() != nullptr) {
312 PrintProperty("dominator", "B", block->GetDominator()->GetBlockId());
313 }
314
315 StartTag("states");
316 StartTag("locals");
317 PrintInt("size", 0);
318 PrintProperty("method", "None");
319 for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
320 AddIndent();
321 HInstruction* instruction = it.Current();
Nicolas Geoffrayb09aacb2014-09-17 18:21:53 +0100322 output_ << instruction->GetId() << " " << GetTypeId(instruction->GetType())
323 << instruction->GetId() << "[ ";
Nicolas Geoffrayf635e632014-05-14 09:43:38 +0100324 for (HInputIterator inputs(instruction); !inputs.Done(); inputs.Advance()) {
325 output_ << inputs.Current()->GetId() << " ";
326 }
327 output_ << "]" << std::endl;
328 }
329 EndTag("locals");
330 EndTag("states");
331
332 StartTag("HIR");
333 PrintInstructions(block->GetPhis());
334 PrintInstructions(block->GetInstructions());
335 EndTag("HIR");
336 EndTag("block");
337 }
338
339 private:
340 std::ostream& output_;
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100341 const char* pass_name_;
Nicolas Geoffray840e5462015-01-07 16:01:24 +0000342 const bool is_after_pass_;
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100343 const CodeGenerator& codegen_;
Nicolas Geoffrayf635e632014-05-14 09:43:38 +0100344 size_t indent_;
345
346 DISALLOW_COPY_AND_ASSIGN(HGraphVisualizerPrinter);
347};
348
349HGraphVisualizer::HGraphVisualizer(std::ostream* output,
350 HGraph* graph,
David Brazdil62e074f2015-04-07 18:09:37 +0100351 const CodeGenerator& codegen)
352 : output_(output), graph_(graph), codegen_(codegen) {}
Nicolas Geoffrayf635e632014-05-14 09:43:38 +0100353
David Brazdil62e074f2015-04-07 18:09:37 +0100354void HGraphVisualizer::PrintHeader(const char* method_name) const {
355 DCHECK(output_ != nullptr);
Nicolas Geoffray840e5462015-01-07 16:01:24 +0000356 HGraphVisualizerPrinter printer(graph_, *output_, "", true, codegen_);
Nicolas Geoffrayf635e632014-05-14 09:43:38 +0100357 printer.StartTag("compilation");
Nicolas Geoffraye53798a2014-12-01 10:31:54 +0000358 printer.PrintProperty("name", method_name);
359 printer.PrintProperty("method", method_name);
Nicolas Geoffray0d3f5782014-05-14 09:43:38 +0100360 printer.PrintTime("date");
361 printer.EndTag("compilation");
362}
363
David Brazdilee690a32014-12-01 17:04:16 +0000364void HGraphVisualizer::DumpGraph(const char* pass_name, bool is_after_pass) const {
David Brazdil5e8b1372015-01-23 14:39:08 +0000365 DCHECK(output_ != nullptr);
366 if (!graph_->GetBlocks().IsEmpty()) {
Nicolas Geoffray840e5462015-01-07 16:01:24 +0000367 HGraphVisualizerPrinter printer(graph_, *output_, pass_name, is_after_pass, codegen_);
David Brazdilee690a32014-12-01 17:04:16 +0000368 printer.Run();
Nicolas Geoffrayf635e632014-05-14 09:43:38 +0100369 }
Nicolas Geoffrayf635e632014-05-14 09:43:38 +0100370}
371
372} // namespace art