Home | History | Annotate | Download | only in optimizing
      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