Avoid generating jmp +0.

When a block branches to a non-following block, but blocks
in-between do branch to it, we can avoid doing the branch.

Change-Id: I9b343f662a4efc718cd4b58168f93162a24e1219
diff --git a/compiler/optimizing/code_generator.cc b/compiler/optimizing/code_generator.cc
index d0739a6..bf3ed14 100644
--- a/compiler/optimizing/code_generator.cc
+++ b/compiler/optimizing/code_generator.cc
@@ -40,6 +40,16 @@
   return mirror::ObjectArray<mirror::Object>::OffsetOfElement(index).SizeValue();
 }
 
+static bool IsSingleGoto(HBasicBlock* block) {
+  HLoopInformation* loop_info = block->GetLoopInformation();
+  // TODO: Remove the null check b/19084197.
+  return (block->GetFirstInstruction() != nullptr)
+      && (block->GetFirstInstruction() == block->GetLastInstruction())
+      && block->GetLastInstruction()->IsGoto()
+      // Back edges generate the suspend check.
+      && (loop_info == nullptr || !loop_info->IsBackEdge(block));
+}
+
 void CodeGenerator::CompileBaseline(CodeAllocator* allocator, bool is_leaf) {
   Initialize();
   if (!is_leaf) {
@@ -56,12 +66,38 @@
   CompileInternal(allocator, /* is_baseline */ true);
 }
 
+bool CodeGenerator::GoesToNextBlock(HBasicBlock* current, HBasicBlock* next) const {
+  DCHECK_EQ(block_order_->Get(current_block_index_), current);
+  return GetNextBlockToEmit() == FirstNonEmptyBlock(next);
+}
+
+HBasicBlock* CodeGenerator::GetNextBlockToEmit() const {
+  for (size_t i = current_block_index_ + 1; i < block_order_->Size(); ++i) {
+    HBasicBlock* block = block_order_->Get(i);
+    if (!IsSingleGoto(block)) {
+      return block;
+    }
+  }
+  return nullptr;
+}
+
+HBasicBlock* CodeGenerator::FirstNonEmptyBlock(HBasicBlock* block) const {
+  while (IsSingleGoto(block)) {
+    block = block->GetSuccessors().Get(0);
+  }
+  return block;
+}
+
 void CodeGenerator::CompileInternal(CodeAllocator* allocator, bool is_baseline) {
   HGraphVisitor* instruction_visitor = GetInstructionVisitor();
   DCHECK_EQ(current_block_index_, 0u);
   GenerateFrameEntry();
   for (size_t e = block_order_->Size(); current_block_index_ < e; ++current_block_index_) {
     HBasicBlock* block = block_order_->Get(current_block_index_);
+    // Don't generate code for an empty block. Its predecessors will branch to its successor
+    // directly. Also, the label of that block will not be emitted, so this helps catch
+    // errors where we reference that label.
+    if (IsSingleGoto(block)) continue;
     Bind(block);
     for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
       HInstruction* current = it.Current();
@@ -338,12 +374,6 @@
   }
 }
 
-bool CodeGenerator::GoesToNextBlock(HBasicBlock* current, HBasicBlock* next) const {
-  DCHECK_EQ(block_order_->Get(current_block_index_), current);
-  return (current_block_index_ < block_order_->Size() - 1)
-      && (block_order_->Get(current_block_index_ + 1) == next);
-}
-
 CodeGenerator* CodeGenerator::Create(HGraph* graph,
                                      InstructionSet instruction_set,
                                      const InstructionSetFeatures& isa_features,
diff --git a/compiler/optimizing/code_generator.h b/compiler/optimizing/code_generator.h
index efd0c84..6c78f10 100644
--- a/compiler/optimizing/code_generator.h
+++ b/compiler/optimizing/code_generator.h
@@ -91,6 +91,8 @@
 
   HGraph* GetGraph() const { return graph_; }
 
+  HBasicBlock* GetNextBlockToEmit() const;
+  HBasicBlock* FirstNonEmptyBlock(HBasicBlock* block) const;
   bool GoesToNextBlock(HBasicBlock* current, HBasicBlock* next) const;
 
   size_t GetStackSlotOfParameter(HParameterValue* parameter) const {
@@ -314,6 +316,14 @@
     return GetFrameSize() == (CallPushesPC() ? GetWordSize() : 0);
   }
 
+  // Arm64 has its own type for a label, so we need to templatize this method
+  // to share the logic.
+  template <typename T>
+  T* CommonGetLabelOf(T* raw_pointer_to_labels_array, HBasicBlock* block) const {
+    block = FirstNonEmptyBlock(block);
+    return raw_pointer_to_labels_array + block->GetBlockId();
+  }
+
   // Frame size required for this method.
   uint32_t frame_size_;
   uint32_t core_spill_mask_;
diff --git a/compiler/optimizing/code_generator_arm.h b/compiler/optimizing/code_generator_arm.h
index 47d81ff..f1a3729 100644
--- a/compiler/optimizing/code_generator_arm.h
+++ b/compiler/optimizing/code_generator_arm.h
@@ -252,7 +252,7 @@
   void MarkGCCard(Register temp, Register card, Register object, Register value);
 
   Label* GetLabelOf(HBasicBlock* block) const {
-    return block_labels_.GetRawStorage() + block->GetBlockId();
+    return CommonGetLabelOf<Label>(block_labels_.GetRawStorage(), block);
   }
 
   void Initialize() OVERRIDE {
diff --git a/compiler/optimizing/code_generator_arm64.h b/compiler/optimizing/code_generator_arm64.h
index 2e937e2..afb7fc3 100644
--- a/compiler/optimizing/code_generator_arm64.h
+++ b/compiler/optimizing/code_generator_arm64.h
@@ -214,7 +214,7 @@
   void Bind(HBasicBlock* block) OVERRIDE;
 
   vixl::Label* GetLabelOf(HBasicBlock* block) const {
-    return block_labels_ + block->GetBlockId();
+    return CommonGetLabelOf<vixl::Label>(block_labels_, block);
   }
 
   void Move(HInstruction* instruction, Location location, HInstruction* move_for) OVERRIDE;
diff --git a/compiler/optimizing/code_generator_x86.h b/compiler/optimizing/code_generator_x86.h
index 107ddaf..f5a9b7d 100644
--- a/compiler/optimizing/code_generator_x86.h
+++ b/compiler/optimizing/code_generator_x86.h
@@ -234,7 +234,7 @@
   void LoadCurrentMethod(Register reg);
 
   Label* GetLabelOf(HBasicBlock* block) const {
-    return block_labels_.GetRawStorage() + block->GetBlockId();
+    return CommonGetLabelOf<Label>(block_labels_.GetRawStorage(), block);
   }
 
   void Initialize() OVERRIDE {
diff --git a/compiler/optimizing/code_generator_x86_64.h b/compiler/optimizing/code_generator_x86_64.h
index dbdbf86..707c999 100644
--- a/compiler/optimizing/code_generator_x86_64.h
+++ b/compiler/optimizing/code_generator_x86_64.h
@@ -232,7 +232,7 @@
   void LoadCurrentMethod(CpuRegister reg);
 
   Label* GetLabelOf(HBasicBlock* block) const {
-    return block_labels_.GetRawStorage() + block->GetBlockId();
+    return CommonGetLabelOf<Label>(block_labels_.GetRawStorage(), block);
   }
 
   void Initialize() OVERRIDE {