Remove jumps over empty blocks.

After contracting a node reorder it as unreachable even if it
hasn't yet been placed.

BUG=
R=jvoung@chromium.org, jvoung, stichnot

Review URL: https://codereview.chromium.org/1246173003.
diff --git a/src/IceCfg.cpp b/src/IceCfg.cpp
index f7b1a8c..7e91508 100644
--- a/src/IceCfg.cpp
+++ b/src/IceCfg.cpp
@@ -259,6 +259,8 @@
 // placed, while maintaining the same relative ordering among already
 // placed nodes.
 void Cfg::reorderNodes() {
+  // TODO(ascull): it would be nice if the switch tests were always followed
+  // by the default case to allow for fall through.
   typedef std::list<CfgNode *> PlacedList;
   PlacedList Placed;      // Nodes with relative placement locked down
   PlacedList Unreachable; // Unreachable nodes
@@ -271,6 +273,14 @@
     // --PlaceIndex and assert() statements before moving to the next
     // node.
     do {
+      if (Node != getEntryNode() && Node->getInEdges().empty()) {
+        // The node has essentially been deleted since it is not a
+        // successor of any other node.
+        Unreachable.push_back(Node);
+        PlaceIndex[Node->getIndex()] = Unreachable.end();
+        Node->setNeedsPlacement(false);
+        continue;
+      }
       if (!Node->needsPlacement()) {
         // Add to the end of the Placed list.
         Placed.push_back(Node);
@@ -278,13 +288,6 @@
         continue;
       }
       Node->setNeedsPlacement(false);
-      if (Node != getEntryNode() && Node->getInEdges().empty()) {
-        // The node has essentially been deleted since it is not a
-        // successor of any other node.
-        Unreachable.push_back(Node);
-        PlaceIndex[Node->getIndex()] = Unreachable.end();
-        continue;
-      }
       // Assume for now that the unplaced node is from edge-splitting
       // and therefore has 1 in-edge and 1 out-edge (actually, possibly
       // more than 1 in-edge if the predecessor node was contracted).
@@ -521,8 +524,7 @@
 void Cfg::doBranchOpt() {
   TimerMarker T(TimerStack::TT_doBranchOpt, this);
   for (auto I = Nodes.begin(), E = Nodes.end(); I != E; ++I) {
-    auto NextNode = I;
-    ++NextNode;
+    auto NextNode = I + 1;
     (*I)->doBranchOpt(NextNode == E ? nullptr : *NextNode);
   }
 }
diff --git a/src/IceCfgNode.cpp b/src/IceCfgNode.cpp
index 60214c7..a901753 100644
--- a/src/IceCfgNode.cpp
+++ b/src/IceCfgNode.cpp
@@ -730,41 +730,46 @@
   }
   Branch->setDeleted();
   assert(OutEdges.size() == 1);
+  CfgNode *Successor = OutEdges.front();
   // Repoint all this node's in-edges to this node's successor, unless
   // this node's successor is actually itself (in which case the
   // statement "OutEdges.front()->InEdges.push_back(Pred)" could
   // invalidate the iterator over this->InEdges).
-  if (OutEdges.front() != this) {
+  if (Successor != this) {
     for (CfgNode *Pred : InEdges) {
-      for (auto I = Pred->OutEdges.begin(), E = Pred->OutEdges.end(); I != E;
-           ++I) {
-        if (*I == this) {
-          *I = OutEdges.front();
-          OutEdges.front()->InEdges.push_back(Pred);
+      for (CfgNode *&I : Pred->OutEdges) {
+        if (I == this) {
+          I = Successor;
+          Successor->InEdges.push_back(Pred);
         }
       }
       for (Inst &I : Pred->getInsts()) {
         if (!I.isDeleted())
-          I.repointEdges(this, OutEdges.front());
+          I.repointEdges(this, Successor);
       }
     }
+
+    // Remove the in-edge to the successor to allow node reordering to make
+    // better decisions. For example it's more helpful to place a node after
+    // a reachable predecessor than an unreachable one (like the one we just
+    // contracted).
+    Successor->InEdges.erase(
+        std::find(Successor->InEdges.begin(), Successor->InEdges.end(), this));
   }
   InEdges.clear();
-  // Don't bother removing the single out-edge, which would also
-  // require finding the corresponding in-edge in the successor and
-  // removing it.
 }
 
 void CfgNode::doBranchOpt(const CfgNode *NextNode) {
   TargetLowering *Target = Func->getTarget();
-  // Check every instruction for a branch optimization opportunity.
-  // It may be more efficient to iterate in reverse and stop after the
-  // first opportunity, unless there is some target lowering where we
-  // have the possibility of multiple such optimizations per block
-  // (currently not the case for x86 lowering).
-  for (Inst &I : Insts) {
+  // Find the first opportunity for branch optimization (which will be the last
+  // instruction in the block) and stop. This is sufficient unless there is some
+  // target lowering where we have the possibility of multiple optimizations per
+  // block. Take care with switch lowering as there are multiple unconditional
+  // branches and only the last can be deleted.
+  for (Inst &I : reverse_range(Insts)) {
     if (!I.isDeleted()) {
       Target->doBranchOpt(&I, NextNode);
+      return;
     }
   }
 }
diff --git a/tests_lit/llvm2ice_tests/adv-switch-opt.ll b/tests_lit/llvm2ice_tests/adv-switch-opt.ll
index 7aa832a..1d10931 100644
--- a/tests_lit/llvm2ice_tests/adv-switch-opt.ll
+++ b/tests_lit/llvm2ice_tests/adv-switch-opt.ll
@@ -143,7 +143,6 @@
 ; CHECK-NEXT: je
 ; CHECK-NEXT: cmp {{.*}},0xea
 ; CHECK-NEXT: je
-; CHECK-NEXT: jmp
 
 ; Test for correct 64-bit lowering.
 ; TODO(ascull): this should generate better code like the 32-bit version
diff --git a/tests_lit/llvm2ice_tests/branch-opt.ll b/tests_lit/llvm2ice_tests/branch-opt.ll
index 94bcd0f..24b6adb 100644
--- a/tests_lit/llvm2ice_tests/branch-opt.ll
+++ b/tests_lit/llvm2ice_tests/branch-opt.ll
@@ -169,3 +169,37 @@
 ; ARM32OM1: bx lr
 ; ARM32OM1: bl
 ; ARM32OM1: bx lr
+
+; Unconditional branches to the block after a contracted block should be
+; removed.
+define void @testUncondToBlockAfterContract() {
+entry:
+  call void @dummy()
+  br label %target
+contract:
+  br label %target
+target:
+  call void @dummy()
+  ret void
+}
+
+; O2-LABEL: testUncondToBlockAfterContract
+; O2: call
+; There will be nops for bundle align to end (for NaCl), but there should
+; not be a branch.
+; O2-NOT: j
+; O2: call
+
+; OM1-LABEL: testUncondToBlockAfterContract
+; OM1: call
+; OM1-NEXT: jmp
+; OM1: call
+
+; ARM32O2-LABEL: testUncondToBlockAfterContract
+; ARM32O2: bl {{.*}} dummy
+; ARM32O2-NEXT: bl {{.*}} dummy
+
+; ARM32OM1-LABEL: testUncondToBlockAfterContract
+; ARM32OM1: bl {{.*}} dummy
+; ARM32OM1-NEXT: b
+; ARM32OM1-NEXT: bl {{.*}} dummy