Refactor handling of conditional branches with known result.

Detect IF_cc and IF_ccZ instructions with known results in
the basic block optimization phase (instead for the codegen
phase) and replace them with GOTO/NOP. Kill blocks that are
unreachable as a result.

Change-Id: I169c2fa6f1e8af685f4f3a7fe622f5da862ce329
diff --git a/compiler/dex/mir_optimization.cc b/compiler/dex/mir_optimization.cc
index 1f630f7..55f2abc 100644
--- a/compiler/dex/mir_optimization.cc
+++ b/compiler/dex/mir_optimization.cc
@@ -399,6 +399,28 @@
   return compiler_temp;
 }
 
+static bool EvaluateBranch(Instruction::Code opcode, int32_t src1, int32_t src2) {
+  bool is_taken;
+  switch (opcode) {
+    case Instruction::IF_EQ: is_taken = (src1 == src2); break;
+    case Instruction::IF_NE: is_taken = (src1 != src2); break;
+    case Instruction::IF_LT: is_taken = (src1 < src2); break;
+    case Instruction::IF_GE: is_taken = (src1 >= src2); break;
+    case Instruction::IF_GT: is_taken = (src1 > src2); break;
+    case Instruction::IF_LE: is_taken = (src1 <= src2); break;
+    case Instruction::IF_EQZ: is_taken = (src1 == 0); break;
+    case Instruction::IF_NEZ: is_taken = (src1 != 0); break;
+    case Instruction::IF_LTZ: is_taken = (src1 < 0); break;
+    case Instruction::IF_GEZ: is_taken = (src1 >= 0); break;
+    case Instruction::IF_GTZ: is_taken = (src1 > 0); break;
+    case Instruction::IF_LEZ: is_taken = (src1 <= 0); break;
+    default:
+      LOG(FATAL) << "Unexpected opcode " << opcode;
+      UNREACHABLE();
+  }
+  return is_taken;
+}
+
 /* Do some MIR-level extended basic block optimizations */
 bool MIRGraph::BasicBlockOpt(BasicBlock* bb) {
   if (bb->block_type == kDead) {
@@ -424,6 +446,46 @@
       // Look for interesting opcodes, skip otherwise
       Instruction::Code opcode = mir->dalvikInsn.opcode;
       switch (opcode) {
+        case Instruction::IF_EQ:
+        case Instruction::IF_NE:
+        case Instruction::IF_LT:
+        case Instruction::IF_GE:
+        case Instruction::IF_GT:
+        case Instruction::IF_LE:
+          if (!IsConst(mir->ssa_rep->uses[1])) {
+            break;
+          }
+          FALLTHROUGH_INTENDED;
+        case Instruction::IF_EQZ:
+        case Instruction::IF_NEZ:
+        case Instruction::IF_LTZ:
+        case Instruction::IF_GEZ:
+        case Instruction::IF_GTZ:
+        case Instruction::IF_LEZ:
+          // Result known at compile time?
+          if (IsConst(mir->ssa_rep->uses[0])) {
+            int32_t rhs = (mir->ssa_rep->num_uses == 2) ? ConstantValue(mir->ssa_rep->uses[1]) : 0;
+            bool is_taken = EvaluateBranch(opcode, ConstantValue(mir->ssa_rep->uses[0]), rhs);
+            BasicBlockId edge_to_kill = is_taken ? bb->fall_through : bb->taken;
+            if (is_taken) {
+              // Replace with GOTO.
+              bb->fall_through = NullBasicBlockId;
+              mir->dalvikInsn.opcode = Instruction::GOTO;
+              mir->dalvikInsn.vA =
+                  IsInstructionIfCc(opcode) ? mir->dalvikInsn.vC : mir->dalvikInsn.vB;
+            } else {
+              // Make NOP.
+              bb->taken = NullBasicBlockId;
+              mir->dalvikInsn.opcode = static_cast<Instruction::Code>(kMirOpNop);
+            }
+            mir->ssa_rep->num_uses = 0;
+            BasicBlock* successor_to_unlink = GetBasicBlock(edge_to_kill);
+            successor_to_unlink->ErasePredecessor(bb->id);
+            if (successor_to_unlink->predecessors.empty()) {
+              successor_to_unlink->KillUnreachable(this);
+            }
+          }
+          break;
         case Instruction::CMPL_FLOAT:
         case Instruction::CMPL_DOUBLE:
         case Instruction::CMPG_FLOAT:
diff --git a/compiler/dex/quick/codegen_util.cc b/compiler/dex/quick/codegen_util.cc
index 1cde01e..58bcee2 100644
--- a/compiler/dex/quick/codegen_util.cc
+++ b/compiler/dex/quick/codegen_util.cc
@@ -922,28 +922,6 @@
   NewLIR1(kPseudoDalvikByteCodeBoundary, WrapPointer(ArenaStrdup(inst_str)));
 }
 
-bool Mir2Lir::EvaluateBranch(Instruction::Code opcode, int32_t src1, int32_t src2) {
-  bool is_taken;
-  switch (opcode) {
-    case Instruction::IF_EQ: is_taken = (src1 == src2); break;
-    case Instruction::IF_NE: is_taken = (src1 != src2); break;
-    case Instruction::IF_LT: is_taken = (src1 < src2); break;
-    case Instruction::IF_GE: is_taken = (src1 >= src2); break;
-    case Instruction::IF_GT: is_taken = (src1 > src2); break;
-    case Instruction::IF_LE: is_taken = (src1 <= src2); break;
-    case Instruction::IF_EQZ: is_taken = (src1 == 0); break;
-    case Instruction::IF_NEZ: is_taken = (src1 != 0); break;
-    case Instruction::IF_LTZ: is_taken = (src1 < 0); break;
-    case Instruction::IF_GEZ: is_taken = (src1 >= 0); break;
-    case Instruction::IF_GTZ: is_taken = (src1 > 0); break;
-    case Instruction::IF_LEZ: is_taken = (src1 <= 0); break;
-    default:
-      LOG(FATAL) << "Unexpected opcode " << opcode;
-      UNREACHABLE();
-  }
-  return is_taken;
-}
-
 // Convert relation of src1/src2 to src2/src1
 ConditionCode Mir2Lir::FlipComparisonOrder(ConditionCode before) {
   ConditionCode res;
diff --git a/compiler/dex/quick/mir_to_lir.cc b/compiler/dex/quick/mir_to_lir.cc
index 0d30927..68856cd 100644
--- a/compiler/dex/quick/mir_to_lir.cc
+++ b/compiler/dex/quick/mir_to_lir.cc
@@ -657,24 +657,12 @@
     case Instruction::IF_GT:
     case Instruction::IF_LE: {
       LIR* taken = &label_list[bb->taken];
-      // Result known at compile time?
-      if (rl_src[0].is_const && rl_src[1].is_const) {
-        bool is_taken = EvaluateBranch(opcode, mir_graph_->ConstantValue(rl_src[0].orig_sreg),
-                                       mir_graph_->ConstantValue(rl_src[1].orig_sreg));
-        BasicBlockId target_id = is_taken ? bb->taken : bb->fall_through;
-        if (mir_graph_->IsBackedge(bb, target_id) &&
-            (kLeafOptimization || !mir_graph_->HasSuspendTestBetween(bb, target_id))) {
-          GenSuspendTest(opt_flags);
-        }
-        OpUnconditionalBranch(&label_list[target_id]);
-      } else {
-        if (mir_graph_->IsBackwardsBranch(bb) &&
-            (kLeafOptimization || !mir_graph_->HasSuspendTestBetween(bb, bb->taken) ||
-             !mir_graph_->HasSuspendTestBetween(bb, bb->fall_through))) {
-          GenSuspendTest(opt_flags);
-        }
-        GenCompareAndBranch(opcode, rl_src[0], rl_src[1], taken);
+      if (mir_graph_->IsBackwardsBranch(bb) &&
+          (kLeafOptimization || !mir_graph_->HasSuspendTestBetween(bb, bb->taken) ||
+           !mir_graph_->HasSuspendTestBetween(bb, bb->fall_through))) {
+        GenSuspendTest(opt_flags);
       }
+      GenCompareAndBranch(opcode, rl_src[0], rl_src[1], taken);
       break;
     }
     case Instruction::IF_EQZ:
@@ -684,23 +672,12 @@
     case Instruction::IF_GTZ:
     case Instruction::IF_LEZ: {
       LIR* taken = &label_list[bb->taken];
-      // Result known at compile time?
-      if (rl_src[0].is_const) {
-        bool is_taken = EvaluateBranch(opcode, mir_graph_->ConstantValue(rl_src[0].orig_sreg), 0);
-        BasicBlockId target_id = is_taken ? bb->taken : bb->fall_through;
-        if (mir_graph_->IsBackedge(bb, target_id) &&
-            (kLeafOptimization || !mir_graph_->HasSuspendTestBetween(bb, target_id))) {
-          GenSuspendTest(opt_flags);
-        }
-        OpUnconditionalBranch(&label_list[target_id]);
-      } else {
-        if (mir_graph_->IsBackwardsBranch(bb) &&
-            (kLeafOptimization || !mir_graph_->HasSuspendTestBetween(bb, bb->taken) ||
-             !mir_graph_->HasSuspendTestBetween(bb, bb->fall_through))) {
-          GenSuspendTest(opt_flags);
-        }
-        GenCompareZeroAndBranch(opcode, rl_src[0], taken);
+      if (mir_graph_->IsBackwardsBranch(bb) &&
+          (kLeafOptimization || !mir_graph_->HasSuspendTestBetween(bb, bb->taken) ||
+           !mir_graph_->HasSuspendTestBetween(bb, bb->fall_through))) {
+        GenSuspendTest(opt_flags);
       }
+      GenCompareZeroAndBranch(opcode, rl_src[0], taken);
       break;
     }
 
diff --git a/compiler/dex/quick/mir_to_lir.h b/compiler/dex/quick/mir_to_lir.h
index 6847717..88b260c 100644
--- a/compiler/dex/quick/mir_to_lir.h
+++ b/compiler/dex/quick/mir_to_lir.h
@@ -666,7 +666,6 @@
     void MarkBoundary(DexOffset offset, const char* inst_str);
     void NopLIR(LIR* lir);
     void UnlinkLIR(LIR* lir);
-    bool EvaluateBranch(Instruction::Code opcode, int src1, int src2);
     bool IsInexpensiveConstant(RegLocation rl_src);
     ConditionCode FlipComparisonOrder(ConditionCode before);
     ConditionCode NegateComparison(ConditionCode before);