Merge "Add a compilation tracing mechanism to the new compiler."
diff --git a/compiler/Android.mk b/compiler/Android.mk
index 1b70d59..8592aaa 100644
--- a/compiler/Android.mk
+++ b/compiler/Android.mk
@@ -82,6 +82,7 @@
 	optimizing/code_generator.cc \
 	optimizing/code_generator_arm.cc \
 	optimizing/code_generator_x86.cc \
+	optimizing/graph_visualizer.cc \
 	optimizing/nodes.cc \
 	optimizing/optimizing_compiler.cc \
 	optimizing/ssa_builder.cc \
diff --git a/compiler/compilers.h b/compiler/compilers.h
index 3ca78c9..e523d64 100644
--- a/compiler/compilers.h
+++ b/compiler/compilers.h
@@ -73,7 +73,7 @@
 
 class OptimizingCompiler FINAL : public QuickCompiler {
  public:
-  explicit OptimizingCompiler(CompilerDriver* driver) : QuickCompiler(driver) { }
+  explicit OptimizingCompiler(CompilerDriver* driver);
 
   CompiledMethod* Compile(const DexFile::CodeItem* code_item,
                           uint32_t access_flags,
@@ -92,6 +92,8 @@
                              const DexFile& dex_file) const;
 
  private:
+  UniquePtr<std::ostream> visualizer_output_;
+
   DISALLOW_COPY_AND_ASSIGN(OptimizingCompiler);
 };
 
diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc
index b0aa63b..2c2564d 100644
--- a/compiler/optimizing/builder.cc
+++ b/compiler/optimizing/builder.cc
@@ -311,6 +311,10 @@
     }
   }
 
+  if (return_type == Primitive::kPrimDouble || return_type == Primitive::kPrimFloat) {
+    return false;
+  }
+
   DCHECK_EQ(argument_index, number_of_arguments);
   current_block_->AddInstruction(invoke);
   return true;
diff --git a/compiler/optimizing/code_generator.cc b/compiler/optimizing/code_generator.cc
index bbebd3a..beafbcc 100644
--- a/compiler/optimizing/code_generator.cc
+++ b/compiler/optimizing/code_generator.cc
@@ -47,7 +47,7 @@
   Bind(GetLabelOf(block));
   HGraphVisitor* location_builder = GetLocationBuilder();
   HGraphVisitor* instruction_visitor = GetInstructionVisitor();
-  for (HInstructionIterator it(*block->GetInstructions()); !it.Done(); it.Advance()) {
+  for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
     HInstruction* current = it.Current();
     current->Accept(location_builder);
     InitLocations(current);
diff --git a/compiler/optimizing/graph_visualizer.cc b/compiler/optimizing/graph_visualizer.cc
new file mode 100644
index 0000000..a7604be
--- /dev/null
+++ b/compiler/optimizing/graph_visualizer.cc
@@ -0,0 +1,199 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "graph_visualizer.h"
+
+#include "driver/dex_compilation_unit.h"
+#include "nodes.h"
+
+namespace art {
+
+/**
+ * HGraph visitor to generate a file suitable for the c1visualizer tool and IRHydra.
+ */
+class HGraphVisualizerPrinter : public HGraphVisitor {
+ public:
+  HGraphVisualizerPrinter(HGraph* graph, std::ostream& output)
+      : HGraphVisitor(graph), output_(output), indent_(0) {}
+
+  void StartTag(const char* name) {
+    AddIndent();
+    output_ << "begin_" << name << std::endl;
+    indent_++;
+  }
+
+  void EndTag(const char* name) {
+    indent_--;
+    AddIndent();
+    output_ << "end_" << name << std::endl;
+  }
+
+  void PrintProperty(const char* name, const char* property) {
+    AddIndent();
+    output_ << name << " \"" << property << "\"" << std::endl;
+  }
+
+  void PrintProperty(const char* name, const char* property, int id) {
+    AddIndent();
+    output_ << name << " \"" << property << id << "\"" << std::endl;
+  }
+
+  void PrintEmptyProperty(const char* name) {
+    AddIndent();
+    output_ << name << std::endl;
+  }
+
+  void PrintTime(const char* name) {
+    AddIndent();
+    output_ << name << " " << time(NULL) << std::endl;
+  }
+
+  void PrintInt(const char* name, int value) {
+    AddIndent();
+    output_ << name << " " << value << std::endl;
+  }
+
+  void AddIndent() {
+    for (size_t i = 0; i < indent_; ++i) {
+      output_ << "  ";
+    }
+  }
+
+  void PrintPredecessors(HBasicBlock* block) {
+    AddIndent();
+    output_ << "predecessors";
+    for (size_t i = 0, e = block->GetPredecessors().Size(); i < e; ++i) {
+      HBasicBlock* predecessor = block->GetPredecessors().Get(i);
+      output_ << " \"B" << predecessor->GetBlockId() << "\" ";
+    }
+    output_<< std::endl;
+  }
+
+  void PrintSuccessors(HBasicBlock* block) {
+    AddIndent();
+    output_ << "successors";
+    for (size_t i = 0, e = block->GetSuccessors().Size(); i < e; ++i) {
+      HBasicBlock* successor = block->GetSuccessors().Get(i);
+      output_ << " \"B" << successor->GetBlockId() << "\" ";
+    }
+    output_<< std::endl;
+  }
+
+
+  void VisitInstruction(HInstruction* instruction) {
+    output_ << instruction->DebugName();
+    if (instruction->InputCount() > 0) {
+      output_ << " [ ";
+      for (HInputIterator inputs(instruction); !inputs.Done(); inputs.Advance()) {
+        output_ << "v" << inputs.Current()->GetId() << " ";
+      }
+      output_ << "]";
+    }
+  }
+
+  void PrintInstructions(const HInstructionList& list) {
+    const char* kEndInstructionMarker = "<|@";
+    for (HInstructionIterator it(list); !it.Done(); it.Advance()) {
+      HInstruction* instruction = it.Current();
+      AddIndent();
+      int bci = 0;
+      output_ << bci << " " << instruction->NumberOfUses() << " v" << instruction->GetId() << " ";
+      instruction->Accept(this);
+      output_ << kEndInstructionMarker << std::endl;
+    }
+  }
+
+  void Run(const char* pass_name) {
+    StartTag("cfg");
+    PrintProperty("name", pass_name);
+    VisitInsertionOrder();
+    EndTag("cfg");
+  }
+
+  void VisitBasicBlock(HBasicBlock* block) {
+    StartTag("block");
+    PrintProperty("name", "B", block->GetBlockId());
+    PrintInt("from_bci", -1);
+    PrintInt("to_bci", -1);
+    PrintPredecessors(block);
+    PrintSuccessors(block);
+    PrintEmptyProperty("xhandlers");
+    PrintEmptyProperty("flags");
+    if (block->GetDominator() != nullptr) {
+      PrintProperty("dominator", "B", block->GetDominator()->GetBlockId());
+    }
+
+    StartTag("states");
+    StartTag("locals");
+    PrintInt("size", 0);
+    PrintProperty("method", "None");
+    for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
+      AddIndent();
+      HInstruction* instruction = it.Current();
+      output_ << instruction->GetId() << " v" << instruction->GetId() << "[ ";
+      for (HInputIterator inputs(instruction); !inputs.Done(); inputs.Advance()) {
+        output_ << inputs.Current()->GetId() << " ";
+      }
+      output_ << "]" << std::endl;
+    }
+    EndTag("locals");
+    EndTag("states");
+
+    StartTag("HIR");
+    PrintInstructions(block->GetPhis());
+    PrintInstructions(block->GetInstructions());
+    EndTag("HIR");
+    EndTag("block");
+  }
+
+ private:
+  std::ostream& output_;
+  size_t indent_;
+
+  DISALLOW_COPY_AND_ASSIGN(HGraphVisualizerPrinter);
+};
+
+HGraphVisualizer::HGraphVisualizer(std::ostream* output,
+                                   HGraph* graph,
+                                   const char* string_filter,
+                                   const DexCompilationUnit& cu)
+    : output_(output), graph_(graph), is_enabled_(false) {
+  if (output == nullptr) {
+    return;
+  }
+  std::string pretty_name = PrettyMethod(cu.GetDexMethodIndex(), *cu.GetDexFile());
+  if (pretty_name.find(string_filter) == std::string::npos) {
+    return;
+  }
+
+  is_enabled_ = true;
+  HGraphVisualizerPrinter printer(graph, *output_);
+  printer.StartTag("compilation");
+  printer.PrintProperty("name", pretty_name.c_str());
+  printer.PrintProperty("method", pretty_name.c_str());
+  printer.PrintTime("date");
+  printer.EndTag("compilation");
+}
+
+void HGraphVisualizer::DumpGraph(const char* pass_name) {
+  if (!is_enabled_) {
+    return;
+  }
+  HGraphVisualizerPrinter printer(graph_, *output_);
+  printer.Run(pass_name);
+}
+
+}  // namespace art
diff --git a/compiler/optimizing/graph_visualizer.h b/compiler/optimizing/graph_visualizer.h
new file mode 100644
index 0000000..433d55d
--- /dev/null
+++ b/compiler/optimizing/graph_visualizer.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_COMPILER_OPTIMIZING_GRAPH_VISUALIZER_H_
+#define ART_COMPILER_OPTIMIZING_GRAPH_VISUALIZER_H_
+
+#include "utils/allocation.h"
+
+namespace art {
+
+class DexCompilationUnit;
+class HGraph;
+
+/**
+ * If enabled, emits compilation information suitable for the c1visualizer tool
+ * and IRHydra.
+ * Currently only works if the compiler is single threaded.
+ */
+class HGraphVisualizer : public ValueObject {
+ public:
+  /**
+   * If output is not null, and the method name of the dex compilation
+   * unit contains `string_filter`, the compilation information will be
+   * emitted.
+   */
+  HGraphVisualizer(std::ostream* output,
+                   HGraph* graph,
+                   const char* string_filter,
+                   const DexCompilationUnit& cu);
+
+  /**
+   * If this visualizer is enabled, emit the compilation information
+   * in `output_`.
+   */
+  void DumpGraph(const char* pass_name);
+
+ private:
+  std::ostream* const output_;
+  HGraph* const graph_;
+
+  // Is true when `output_` is not null, and the compiled method's name
+  // contains the string_filter given in the constructor.
+  bool is_enabled_;
+
+  DISALLOW_COPY_AND_ASSIGN(HGraphVisualizer);
+};
+
+}  // namespace art
+
+#endif  // ART_COMPILER_OPTIMIZING_GRAPH_VISUALIZER_H_
diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc
index cf2d1ee..afaedd7 100644
--- a/compiler/optimizing/nodes.cc
+++ b/compiler/optimizing/nodes.cc
@@ -37,10 +37,10 @@
       for (size_t j = 0; j < block->GetSuccessors().Size(); ++j) {
         block->GetSuccessors().Get(j)->RemovePredecessor(block, false);
       }
-      for (HInstructionIterator it(*block->GetPhis()); !it.Done(); it.Advance()) {
+      for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
         block->RemovePhi(it.Current()->AsPhi());
       }
-      for (HInstructionIterator it(*block->GetInstructions()); !it.Done(); it.Advance()) {
+      for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
         block->RemoveInstruction(it.Current());
       }
     }
@@ -420,10 +420,10 @@
 }
 
 void HGraphVisitor::VisitBasicBlock(HBasicBlock* block) {
-  for (HInstructionIterator it(*block->GetPhis()); !it.Done(); it.Advance()) {
+  for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
     it.Current()->Accept(this);
   }
-  for (HInstructionIterator it(*block->GetInstructions()); !it.Done(); it.Advance()) {
+  for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
     it.Current()->Accept(this);
   }
 }
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index 081c2bd..27b87ca 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -82,7 +82,7 @@
   void SimplifyCFG();
 
   // Find all natural loops in this graph. Aborts computation and returns false
-  // if one loop is not natural, that is the header does not dominated the back
+  // if one loop is not natural, that is the header does not dominate the back
   // edge.
   bool FindNaturalLoops() const;
 
@@ -268,8 +268,8 @@
 
   HInstruction* GetFirstInstruction() const { return instructions_.first_instruction_; }
   HInstruction* GetLastInstruction() const { return instructions_.last_instruction_; }
-  HInstructionList const* GetInstructions() const { return &instructions_; }
-  HInstructionList const* GetPhis() const { return &phis_; }
+  const HInstructionList& GetInstructions() const { return instructions_; }
+  const HInstructionList& GetPhis() const { return phis_; }
 
   void AddSuccessor(HBasicBlock* block) {
     successors_.Add(block);
@@ -444,6 +444,17 @@
 
   bool HasUses() const { return uses_ != nullptr || env_uses_ != nullptr; }
 
+  size_t NumberOfUses() const {
+    // TODO: Optimize this method if it is used outside of the HGraphTracer.
+    size_t result = 0;
+    HUseListNode<HInstruction>* current = uses_;
+    while (current != nullptr) {
+      current = current->GetTail();
+      ++result;
+    }
+    return result;
+  }
+
   int GetId() const { return id_; }
   void SetId(int id) { id_ = id; }
 
diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc
index a5031e0..f435cb0 100644
--- a/compiler/optimizing/optimizing_compiler.cc
+++ b/compiler/optimizing/optimizing_compiler.cc
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include <fstream>
 #include <stdint.h>
 
 #include "builder.h"
@@ -21,6 +22,7 @@
 #include "compilers.h"
 #include "driver/compiler_driver.h"
 #include "driver/dex_compilation_unit.h"
+#include "graph_visualizer.h"
 #include "nodes.h"
 #include "ssa_liveness_analysis.h"
 #include "utils/arena_allocator.h"
@@ -50,6 +52,22 @@
   DISALLOW_COPY_AND_ASSIGN(CodeVectorAllocator);
 };
 
+/**
+ * If set to true, generates a file suitable for the c1visualizer tool and IRHydra.
+ */
+static bool kIsVisualizerEnabled = false;
+
+/**
+ * Filter to apply to the visualizer. Methods whose name contain that filter will
+ * be in the file.
+ */
+static const char* kStringFilter = "";
+
+OptimizingCompiler::OptimizingCompiler(CompilerDriver* driver) : QuickCompiler(driver) {
+  if (kIsVisualizerEnabled) {
+    visualizer_output_.reset(new std::ofstream("art.cfg"));
+  }
+}
 
 CompiledMethod* OptimizingCompiler::TryCompile(const DexFile::CodeItem* code_item,
                                                uint32_t access_flags,
@@ -70,6 +88,7 @@
   ArenaPool pool;
   ArenaAllocator arena(&pool);
   HGraphBuilder builder(&arena, &dex_compilation_unit, &dex_file);
+
   HGraph* graph = builder.BuildGraph(*code_item);
   if (graph == nullptr) {
     if (shouldCompile) {
@@ -77,6 +96,8 @@
     }
     return nullptr;
   }
+  HGraphVisualizer visualizer(visualizer_output_.get(), graph, kStringFilter, dex_compilation_unit);
+  visualizer.DumpGraph("builder");
 
   InstructionSet instruction_set = GetCompilerDriver()->GetInstructionSet();
   // The optimizing compiler currently does not have a Thumb2 assembler.
@@ -104,6 +125,8 @@
   // Run these phases to get some test coverage.
   graph->BuildDominatorTree();
   graph->TransformToSSA();
+  visualizer.DumpGraph("ssa");
+
   graph->FindNaturalLoops();
   SsaLivenessAnalysis(*graph).Analyze();
 
diff --git a/compiler/optimizing/ssa_builder.cc b/compiler/optimizing/ssa_builder.cc
index 1fc041c..50e3254 100644
--- a/compiler/optimizing/ssa_builder.cc
+++ b/compiler/optimizing/ssa_builder.cc
@@ -30,7 +30,7 @@
   // 2) Set inputs of loop phis.
   for (size_t i = 0; i < loop_headers_.Size(); i++) {
     HBasicBlock* block = loop_headers_.Get(i);
-    for (HInstructionIterator it(*block->GetPhis()); !it.Done(); it.Advance()) {
+    for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
       HPhi* phi = it.Current()->AsPhi();
       for (size_t pred = 0; pred < block->GetPredecessors().Size(); pred++) {
         phi->AddInput(ValueOfLocal(block->GetPredecessors().Get(pred), phi->GetRegNumber()));
@@ -40,7 +40,7 @@
 
   // 3) Clear locals.
   // TODO: Move this to a dead code eliminator phase.
-  for (HInstructionIterator it(*GetGraph()->GetEntryBlock()->GetInstructions());
+  for (HInstructionIterator it(GetGraph()->GetEntryBlock()->GetInstructions());
        !it.Done();
        it.Advance()) {
     HInstruction* current = it.Current();
@@ -106,7 +106,7 @@
   // - HStoreLocal: update current value of the local and remove the instruction.
   // - Instructions that require an environment: populate their environment
   //   with the current values of the locals.
-  for (HInstructionIterator it(*block->GetInstructions()); !it.Done(); it.Advance()) {
+  for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
     it.Current()->Accept(this);
   }
 }
diff --git a/compiler/optimizing/ssa_liveness_analysis.cc b/compiler/optimizing/ssa_liveness_analysis.cc
index 0ab77ca..7c2ec39 100644
--- a/compiler/optimizing/ssa_liveness_analysis.cc
+++ b/compiler/optimizing/ssa_liveness_analysis.cc
@@ -29,14 +29,14 @@
   for (HReversePostOrderIterator it(graph_); !it.Done(); it.Advance()) {
     HBasicBlock* block = it.Current();
 
-    for (HInstructionIterator it(*block->GetPhis()); !it.Done(); it.Advance()) {
+    for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
       HInstruction* current = it.Current();
       if (current->HasUses()) {
         current->SetSsaIndex(ssa_index++);
       }
     }
 
-    for (HInstructionIterator it(*block->GetInstructions()); !it.Done(); it.Advance()) {
+    for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
       HInstruction* current = it.Current();
       if (current->HasUses()) {
         current->SetSsaIndex(ssa_index++);
@@ -73,7 +73,7 @@
     BitVector* kill = GetKillSet(*block);
     BitVector* live_in = GetLiveInSet(*block);
 
-    for (HBackwardInstructionIterator it(*block->GetInstructions()); !it.Done(); it.Advance()) {
+    for (HBackwardInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
       HInstruction* current = it.Current();
       if (current->HasSsaIndex()) {
         kill->SetBit(current->GetSsaIndex());
@@ -99,7 +99,7 @@
       }
     }
 
-    for (HInstructionIterator it(*block->GetPhis()); !it.Done(); it.Advance()) {
+    for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
       HInstruction* current = it.Current();
       if (current->HasSsaIndex()) {
         kill->SetBit(current->GetSsaIndex());
diff --git a/compiler/optimizing/ssa_test.cc b/compiler/optimizing/ssa_test.cc
index 9be2197..415d146 100644
--- a/compiler/optimizing/ssa_test.cc
+++ b/compiler/optimizing/ssa_test.cc
@@ -66,10 +66,10 @@
   int id = 0;
   for (size_t i = 0, e = graph->GetBlocks().Size(); i < e; ++i) {
     HBasicBlock* block = graph->GetBlocks().Get(i);
-    for (HInstructionIterator it(*block->GetPhis()); !it.Done(); it.Advance()) {
+    for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
       it.Current()->SetId(id++);
     }
-    for (HInstructionIterator it(*block->GetInstructions()); !it.Done(); it.Advance()) {
+    for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
       it.Current()->SetId(id++);
     }
   }