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: 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 41 void StartTag(const char* name) { 42 AddIndent(); 43 output_ << "begin_" << name << std::endl; 44 indent_++; 45 } 46 47 void EndTag(const char* name) { 48 indent_--; 49 AddIndent(); 50 output_ << "end_" << name << std::endl; 51 } 52 53 void PrintProperty(const char* name, const char* property) { 54 AddIndent(); 55 output_ << name << " \"" << property << "\"" << std::endl; 56 } 57 58 void PrintProperty(const char* name, const char* property, int id) { 59 AddIndent(); 60 output_ << name << " \"" << property << id << "\"" << std::endl; 61 } 62 63 void PrintEmptyProperty(const char* name) { 64 AddIndent(); 65 output_ << name << std::endl; 66 } 67 68 void PrintTime(const char* name) { 69 AddIndent(); 70 output_ << name << " " << time(NULL) << std::endl; 71 } 72 73 void PrintInt(const char* name, int value) { 74 AddIndent(); 75 output_ << name << " " << value << std::endl; 76 } 77 78 void AddIndent() { 79 for (size_t i = 0; i < indent_; ++i) { 80 output_ << " "; 81 } 82 } 83 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 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 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 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 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 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 184 void Run() { 185 StartTag("cfg"); 186 PrintProperty("name", pass_name_); 187 VisitInsertionOrder(); 188 EndTag("cfg"); 189 } 190 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 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 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 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