Add conditional branches, and build dominator tree.

Change-Id: I4b151a07b72692961235a1419b54b6b45cf54e63
diff --git a/compiler/optimizing/pretty_printer_test.cc b/compiler/optimizing/pretty_printer_test.cc
index 81a0d91..4c8201e 100644
--- a/compiler/optimizing/pretty_printer_test.cc
+++ b/compiler/optimizing/pretty_printer_test.cc
@@ -25,19 +25,10 @@
 
 namespace art {
 
-const uint16_t data[] = { Instruction::RETURN_VOID };
-
-const char* expected =
-    "BasicBlock 0\n"
-    "  Goto\n"
-    "BasicBlock 1\n"
-    "  ReturnVoid\n"
-    "BasicBlock 2\n"
-    "  Exit\n";
-
 class StringPrettyPrinter : public HPrettyPrinter {
  public:
-  explicit StringPrettyPrinter(HGraph* graph) : HPrettyPrinter(graph), str_("") { }
+  explicit StringPrettyPrinter(HGraph* graph)
+      : HPrettyPrinter(graph), str_(""), current_block_(nullptr) { }
 
   virtual void PrintInt(int value) {
     str_ += StringPrintf("%d", value);
@@ -55,33 +46,213 @@
 
   std::string str() const { return str_; }
 
+  virtual void VisitBasicBlock(HBasicBlock* block) {
+    current_block_ = block;
+    HPrettyPrinter::VisitBasicBlock(block);
+  }
+
+  virtual void VisitGoto(HGoto* gota) {
+    str_ += "  Goto ";
+    PrintInt(current_block_->successors()->Get(0)->block_id());
+    PrintNewLine();
+  }
+
  private:
   std::string str_;
+  HBasicBlock* current_block_;
+
   DISALLOW_COPY_AND_ASSIGN(StringPrettyPrinter);
 };
 
-TEST(OptimizerTest, ReturnVoid) {
+
+static void TestCode(const uint16_t* data, int length, const char* expected) {
   ArenaPool pool;
   ArenaAllocator allocator(&pool);
   HGraphBuilder builder(&allocator);
-  HGraph* graph = builder.BuildGraph(data, data + 1);
+  HGraph* graph = builder.BuildGraph(data, data + length);
   ASSERT_NE(graph, nullptr);
   StringPrettyPrinter printer(graph);
   printer.VisitInsertionOrder();
   ASSERT_STREQ(expected, printer.str().c_str());
-
-  const GrowableArray<HBasicBlock*>* blocks = graph->blocks();
-  ASSERT_EQ(blocks->Get(0)->predecessors()->Size(), (size_t)0);
-  ASSERT_EQ(blocks->Get(1)->predecessors()->Size(), (size_t)1);
-  ASSERT_EQ(blocks->Get(1)->predecessors()->Get(0), blocks->Get(0));
-  ASSERT_EQ(blocks->Get(2)->predecessors()->Size(), (size_t)1);
-  ASSERT_EQ(blocks->Get(2)->predecessors()->Get(0), blocks->Get(1));
-
-  ASSERT_EQ(blocks->Get(0)->successors()->Size(), (size_t)1);
-  ASSERT_EQ(blocks->Get(1)->successors()->Get(0), blocks->Get(2));
-  ASSERT_EQ(blocks->Get(1)->successors()->Size(), (size_t)1);
-  ASSERT_EQ(blocks->Get(1)->successors()->Get(0), blocks->Get(2));
-  ASSERT_EQ(blocks->Get(2)->successors()->Size(), (size_t)0);
 }
 
+TEST(PrettyPrinterTest, ReturnVoid) {
+  const uint16_t data[] = { Instruction::RETURN_VOID };
+
+  const char* expected =
+      "BasicBlock 0, succ: 1\n"
+      "  Goto 1\n"
+      "BasicBlock 1, pred: 0, succ: 2\n"
+      "  ReturnVoid\n"
+      "BasicBlock 2, pred: 1\n"
+      "  Exit\n";
+
+  TestCode(data, sizeof(data) / sizeof(uint16_t), expected);
+}
+
+TEST(PrettyPrinterTest, CFG1) {
+  const char* expected =
+    "BasicBlock 0, succ: 1\n"
+    "  Goto 1\n"
+    "BasicBlock 1, pred: 0, succ: 2\n"
+    "  Goto 2\n"
+    "BasicBlock 2, pred: 1, succ: 3\n"
+    "  ReturnVoid\n"
+    "BasicBlock 3, pred: 2\n"
+    "  Exit\n";
+
+  const uint16_t data[] = {
+    Instruction::GOTO | 0x100,
+    Instruction::RETURN_VOID
+  };
+
+  TestCode(data, sizeof(data) / sizeof(uint16_t), expected);
+}
+
+TEST(PrettyPrinterTest, CFG2) {
+  const char* expected =
+    "BasicBlock 0, succ: 1\n"
+    "  Goto 1\n"
+    "BasicBlock 1, pred: 0, succ: 2\n"
+    "  Goto 2\n"
+    "BasicBlock 2, pred: 1, succ: 3\n"
+    "  Goto 3\n"
+    "BasicBlock 3, pred: 2, succ: 4\n"
+    "  ReturnVoid\n"
+    "BasicBlock 4, pred: 3\n"
+    "  Exit\n";
+
+  const uint16_t data[] = {
+    Instruction::GOTO | 0x100,
+    Instruction::GOTO | 0x100,
+    Instruction::RETURN_VOID
+  };
+
+  TestCode(data, sizeof(data) / sizeof(uint16_t), expected);
+}
+
+TEST(PrettyPrinterTest, CFG3) {
+  const char* expected =
+    "BasicBlock 0, succ: 1\n"
+    "  Goto 1\n"
+    "BasicBlock 1, pred: 0, succ: 3\n"
+    "  Goto 3\n"
+    "BasicBlock 2, pred: 3, succ: 4\n"
+    "  ReturnVoid\n"
+    "BasicBlock 3, pred: 1, succ: 2\n"
+    "  Goto 2\n"
+    "BasicBlock 4, pred: 2\n"
+    "  Exit\n";
+
+  const uint16_t data1[] = {
+    Instruction::GOTO | 0x200,
+    Instruction::RETURN_VOID,
+    Instruction::GOTO | 0xFF00
+  };
+
+  TestCode(data1, sizeof(data1) / sizeof(uint16_t), expected);
+
+  const uint16_t data2[] = {
+    Instruction::GOTO_16, 3,
+    Instruction::RETURN_VOID,
+    Instruction::GOTO_16, 0xFFFF
+  };
+
+  TestCode(data2, sizeof(data2) / sizeof(uint16_t), expected);
+
+  const uint16_t data3[] = {
+    Instruction::GOTO_32, 4, 0,
+    Instruction::RETURN_VOID,
+    Instruction::GOTO_32, 0xFFFF, 0xFFFF
+  };
+
+  TestCode(data3, sizeof(data3) / sizeof(uint16_t), expected);
+}
+
+TEST(PrettyPrinterTest, CFG4) {
+  const char* expected =
+    "BasicBlock 0, succ: 1\n"
+    "  Goto 1\n"
+    "BasicBlock 1, pred: 0, 1, succ: 1\n"
+    "  Goto 1\n"
+    "BasicBlock 2\n"
+    "  Exit\n";
+
+  const uint16_t data1[] = {
+    Instruction::NOP,
+    Instruction::GOTO | 0xFF00
+  };
+
+  TestCode(data1, sizeof(data1) / sizeof(uint16_t), expected);
+
+  const uint16_t data2[] = {
+    Instruction::GOTO_32, 0, 0
+  };
+
+  TestCode(data2, sizeof(data2) / sizeof(uint16_t), expected);
+}
+
+TEST(PrettyPrinterTest, CFG5) {
+  const char* expected =
+    "BasicBlock 0, succ: 1\n"
+    "  Goto 1\n"
+    "BasicBlock 1, pred: 0, 2, succ: 3\n"
+    "  ReturnVoid\n"
+    "BasicBlock 2, succ: 1\n"
+    "  Goto 1\n"
+    "BasicBlock 3, pred: 1\n"
+    "  Exit\n";
+
+  const uint16_t data[] = {
+    Instruction::RETURN_VOID,
+    Instruction::GOTO | 0x100,
+    Instruction::GOTO | 0xFE00
+  };
+
+  TestCode(data, sizeof(data) / sizeof(uint16_t), expected);
+}
+
+TEST(OptimizerTest, CFG6) {
+  const char* expected =
+    "BasicBlock 0, succ: 1\n"
+    "  Goto 1\n"
+    "BasicBlock 1, pred: 0, succ: 3, 2\n"
+    "  If\n"
+    "BasicBlock 2, pred: 1, succ: 3\n"
+    "  Goto 3\n"
+    "BasicBlock 3, pred: 1, 2, succ: 4\n"
+    "  ReturnVoid\n"
+    "BasicBlock 4, pred: 3\n"
+    "  Exit\n";
+
+  const uint16_t data[] = {
+    Instruction::IF_EQ, 3,
+    Instruction::GOTO | 0x100,
+    Instruction::RETURN_VOID
+  };
+
+  TestCode(data, sizeof(data) / sizeof(uint16_t), expected);
+}
+
+TEST(OptimizerTest, CFG7) {
+  const char* expected =
+    "BasicBlock 0, succ: 1\n"
+    "  Goto 1\n"
+    "BasicBlock 1, pred: 0, succ: 3, 2\n"
+    "  If\n"
+    "BasicBlock 2, pred: 1, 3, succ: 3\n"
+    "  Goto 3\n"
+    "BasicBlock 3, pred: 1, 2, succ: 2\n"
+    "  Goto 2\n"
+    "BasicBlock 4\n"
+    "  Exit\n";
+
+  const uint16_t data[] = {
+    Instruction::IF_EQ, 3,
+    Instruction::GOTO | 0x100,
+    Instruction::GOTO | 0xFF00
+  };
+
+  TestCode(data, sizeof(data) / sizeof(uint16_t), expected);
+}
 }  // namespace art