1 /*
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 
19 #include "code_generator.h"
20 #include "driver/dex_compilation_unit.h"
21 #include "nodes.h"
22 #include "ssa_liveness_analysis.h"
23 
24 namespace art {
25 
26 /**
27  * HGraph visitor to generate a file suitable for the c1visualizer tool and IRHydra.
28  */
29 class HGraphVisualizerPrinter : public HGraphVisitor {
30  public:
HGraphVisualizerPrinter(HGraph * graph,std::ostream & output,const char * pass_name,const CodeGenerator & codegen)31   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) {}
40 
StartTag(const char * name)41   void StartTag(const char* name) {
42     AddIndent();
43     output_ << "begin_" << name << std::endl;
44     indent_++;
45   }
46 
EndTag(const char * name)47   void EndTag(const char* name) {
48     indent_--;
49     AddIndent();
50     output_ << "end_" << name << std::endl;
51   }
52 
PrintProperty(const char * name,const char * property)53   void PrintProperty(const char* name, const char* property) {
54     AddIndent();
55     output_ << name << " \"" << property << "\"" << std::endl;
56   }
57 
PrintProperty(const char * name,const char * property,int id)58   void PrintProperty(const char* name, const char* property, int id) {
59     AddIndent();
60     output_ << name << " \"" << property << id << "\"" << std::endl;
61   }
62 
PrintEmptyProperty(const char * name)63   void PrintEmptyProperty(const char* name) {
64     AddIndent();
65     output_ << name << std::endl;
66   }
67 
PrintTime(const char * name)68   void PrintTime(const char* name) {
69     AddIndent();
70     output_ << name << " " << time(NULL) << std::endl;
71   }
72 
PrintInt(const char * name,int value)73   void PrintInt(const char* name, int value) {
74     AddIndent();
75     output_ << name << " " << value << std::endl;
76   }
77 
AddIndent()78   void AddIndent() {
79     for (size_t i = 0; i < indent_; ++i) {
80       output_ << "  ";
81     }
82   }
83 
PrintPredecessors(HBasicBlock * block)84   void PrintPredecessors(HBasicBlock* block) {
85     AddIndent();
86     output_ << "predecessors";
87     for (size_t i = 0, e = block->GetPredecessors().Size(); i < e; ++i) {
88       HBasicBlock* predecessor = block->GetPredecessors().Get(i);
89       output_ << " \"B" << predecessor->GetBlockId() << "\" ";
90     }
91     output_<< std::endl;
92   }
93 
PrintSuccessors(HBasicBlock * block)94   void PrintSuccessors(HBasicBlock* block) {
95     AddIndent();
96     output_ << "successors";
97     for (size_t i = 0, e = block->GetSuccessors().Size(); i < e; ++i) {
98       HBasicBlock* successor = block->GetSuccessors().Get(i);
99       output_ << " \"B" << successor->GetBlockId() << "\" ";
100     }
101     output_<< std::endl;
102   }
103 
DumpLocation(Location location,Primitive::Type type)104   void DumpLocation(Location location, Primitive::Type type) {
105     if (location.IsRegister()) {
106       if (type == Primitive::kPrimDouble || type == Primitive::kPrimFloat) {
107         codegen_.DumpFloatingPointRegister(output_, location.reg().RegId());
108       } else {
109         codegen_.DumpCoreRegister(output_, location.reg().RegId());
110       }
111     } else if (location.IsConstant()) {
112       output_ << "constant";
113     } else if (location.IsInvalid()) {
114       output_ << "invalid";
115     } else if (location.IsStackSlot()) {
116       output_ << location.GetStackIndex() << "(sp)";
117     } else {
118       DCHECK(location.IsDoubleStackSlot());
119       output_ << "2x" << location.GetStackIndex() << "(sp)";
120     }
121   }
122 
VisitParallelMove(HParallelMove * instruction)123   void VisitParallelMove(HParallelMove* instruction) {
124     output_ << instruction->DebugName();
125     output_ << " (";
126     for (size_t i = 0, e = instruction->NumMoves(); i < e; ++i) {
127       MoveOperands* move = instruction->MoveOperandsAt(i);
128       DumpLocation(move->GetSource(), Primitive::kPrimInt);
129       output_ << " -> ";
130       DumpLocation(move->GetDestination(), Primitive::kPrimInt);
131       if (i + 1 != e) {
132         output_ << ", ";
133       }
134     }
135     output_ << ")";
136   }
137 
VisitInstruction(HInstruction * instruction)138   void VisitInstruction(HInstruction* instruction) {
139     output_ << instruction->DebugName();
140     if (instruction->InputCount() > 0) {
141       output_ << " [ ";
142       for (HInputIterator inputs(instruction); !inputs.Done(); inputs.Advance()) {
143         output_ << "v" << inputs.Current()->GetId() << " ";
144       }
145       output_ << "]";
146     }
147     if (pass_name_ == kLivenessPassName && instruction->GetLifetimePosition() != kNoLifetime) {
148       output_ << " (liveness: " << instruction->GetLifetimePosition();
149       if (instruction->HasLiveInterval()) {
150         output_ << " ";
151         const LiveInterval& interval = *instruction->GetLiveInterval();
152         interval.Dump(output_);
153       }
154       output_ << ")";
155     } else if (pass_name_ == kRegisterAllocatorPassName) {
156       LocationSummary* locations = instruction->GetLocations();
157       if (locations != nullptr) {
158         output_ << " ( ";
159         for (size_t i = 0; i < instruction->InputCount(); ++i) {
160           DumpLocation(locations->InAt(i), instruction->InputAt(i)->GetType());
161           output_ << " ";
162         }
163         output_ << ")";
164         if (locations->Out().IsValid()) {
165           output_ << " -> ";
166           DumpLocation(locations->Out(), instruction->GetType());
167         }
168       }
169     }
170   }
171 
PrintInstructions(const HInstructionList & list)172   void PrintInstructions(const HInstructionList& list) {
173     const char* kEndInstructionMarker = "<|@";
174     for (HInstructionIterator it(list); !it.Done(); it.Advance()) {
175       HInstruction* instruction = it.Current();
176       AddIndent();
177       int bci = 0;
178       output_ << bci << " " << instruction->NumberOfUses() << " v" << instruction->GetId() << " ";
179       instruction->Accept(this);
180       output_ << kEndInstructionMarker << std::endl;
181     }
182   }
183 
Run()184   void Run() {
185     StartTag("cfg");
186     PrintProperty("name", pass_name_);
187     VisitInsertionOrder();
188     EndTag("cfg");
189   }
190 
VisitBasicBlock(HBasicBlock * block)191   void VisitBasicBlock(HBasicBlock* block) {
192     StartTag("block");
193     PrintProperty("name", "B", block->GetBlockId());
194     if (block->GetLifetimeStart() != kNoLifetime) {
195       // Piggy back on these fields to show the lifetime of the block.
196       PrintInt("from_bci", block->GetLifetimeStart());
197       PrintInt("to_bci", block->GetLifetimeEnd());
198     } else {
199       PrintInt("from_bci", -1);
200       PrintInt("to_bci", -1);
201     }
202     PrintPredecessors(block);
203     PrintSuccessors(block);
204     PrintEmptyProperty("xhandlers");
205     PrintEmptyProperty("flags");
206     if (block->GetDominator() != nullptr) {
207       PrintProperty("dominator", "B", block->GetDominator()->GetBlockId());
208     }
209 
210     StartTag("states");
211     StartTag("locals");
212     PrintInt("size", 0);
213     PrintProperty("method", "None");
214     for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
215       AddIndent();
216       HInstruction* instruction = it.Current();
217       output_ << instruction->GetId() << " v" << instruction->GetId() << "[ ";
218       for (HInputIterator inputs(instruction); !inputs.Done(); inputs.Advance()) {
219         output_ << inputs.Current()->GetId() << " ";
220       }
221       output_ << "]" << std::endl;
222     }
223     EndTag("locals");
224     EndTag("states");
225 
226     StartTag("HIR");
227     PrintInstructions(block->GetPhis());
228     PrintInstructions(block->GetInstructions());
229     EndTag("HIR");
230     EndTag("block");
231   }
232 
233  private:
234   std::ostream& output_;
235   const char* pass_name_;
236   const CodeGenerator& codegen_;
237   size_t indent_;
238 
239   DISALLOW_COPY_AND_ASSIGN(HGraphVisualizerPrinter);
240 };
241 
HGraphVisualizer(std::ostream * output,HGraph * graph,const char * string_filter,const CodeGenerator & codegen,const DexCompilationUnit & cu)242 HGraphVisualizer::HGraphVisualizer(std::ostream* output,
243                                    HGraph* graph,
244                                    const char* string_filter,
245                                    const CodeGenerator& codegen,
246                                    const DexCompilationUnit& cu)
247     : output_(output), graph_(graph), codegen_(codegen), is_enabled_(false) {
248   if (output == nullptr) {
249     return;
250   }
251   std::string pretty_name = PrettyMethod(cu.GetDexMethodIndex(), *cu.GetDexFile());
252   if (pretty_name.find(string_filter) == std::string::npos) {
253     return;
254   }
255 
256   is_enabled_ = true;
257   HGraphVisualizerPrinter printer(graph, *output_, "", codegen_);
258   printer.StartTag("compilation");
259   printer.PrintProperty("name", pretty_name.c_str());
260   printer.PrintProperty("method", pretty_name.c_str());
261   printer.PrintTime("date");
262   printer.EndTag("compilation");
263 }
264 
HGraphVisualizer(std::ostream * output,HGraph * graph,const CodeGenerator & codegen,const char * name)265 HGraphVisualizer::HGraphVisualizer(std::ostream* output,
266                                    HGraph* graph,
267                                    const CodeGenerator& codegen,
268                                    const char* name)
269     : output_(output), graph_(graph), codegen_(codegen), is_enabled_(false) {
270   if (output == nullptr) {
271     return;
272   }
273 
274   is_enabled_ = true;
275   HGraphVisualizerPrinter printer(graph, *output_, "", codegen_);
276   printer.StartTag("compilation");
277   printer.PrintProperty("name", name);
278   printer.PrintProperty("method", name);
279   printer.PrintTime("date");
280   printer.EndTag("compilation");
281 }
282 
DumpGraph(const char * pass_name)283 void HGraphVisualizer::DumpGraph(const char* pass_name) {
284   if (!is_enabled_) {
285     return;
286   }
287   HGraphVisualizerPrinter printer(graph_, *output_, pass_name, codegen_);
288   printer.Run();
289 }
290 
291 }  // namespace art
292