Quick: Eliminate check-cast guaranteed by instance-of.

Eliminate check-cast if the result of an instance-of with
the very same type on the same value is used to branch to
the check-cast's block or a dominator of it.

Note that there already exists a verifier-based elimination
of check-cast but it excludes check-cast on interfaces. This
new optimization works for interface types and, since it's
GVN-based, it can better recognize when the same reference
is used for instance-of and check-cast.

Change-Id: Ib315199805099d1cb0534bb4a90dc51baa409685
diff --git a/compiler/dex/local_value_numbering.cc b/compiler/dex/local_value_numbering.cc
index 99b6683..dc222b5 100644
--- a/compiler/dex/local_value_numbering.cc
+++ b/compiler/dex/local_value_numbering.cc
@@ -1520,7 +1520,6 @@
     case Instruction::GOTO:
     case Instruction::GOTO_16:
     case Instruction::GOTO_32:
-    case Instruction::CHECK_CAST:
     case Instruction::THROW:
     case Instruction::FILL_ARRAY_DATA:
     case Instruction::PACKED_SWITCH:
@@ -1612,9 +1611,32 @@
       HandleInvokeOrClInitOrAcquireOp(mir);
       break;
 
+    case Instruction::INSTANCE_OF: {
+        uint16_t operand = GetOperandValue(mir->ssa_rep->uses[0]);
+        uint16_t type = mir->dalvikInsn.vC;
+        res = gvn_->LookupValue(Instruction::INSTANCE_OF, operand, type, kNoValue);
+        SetOperandValue(mir->ssa_rep->defs[0], res);
+      }
+      break;
+    case Instruction::CHECK_CAST:
+      if (gvn_->CanModify()) {
+        // Check if there was an instance-of operation on the same value and if we are
+        // in a block where its result is true. If so, we can eliminate the check-cast.
+        uint16_t operand = GetOperandValue(mir->ssa_rep->uses[0]);
+        uint16_t type = mir->dalvikInsn.vB;
+        uint16_t cond = gvn_->FindValue(Instruction::INSTANCE_OF, operand, type, kNoValue);
+        if (cond != kNoValue && gvn_->IsTrueInBlock(cond, Id())) {
+          if (gvn_->GetCompilationUnit()->verbose) {
+            LOG(INFO) << "Removing check-cast at 0x" << std::hex << mir->offset;
+          }
+          // Don't use kMirOpNop. Keep the check-cast as it defines the type of the register.
+          mir->optimization_flags |= MIR_IGNORE_CHECK_CAST;
+        }
+      }
+      break;
+
     case Instruction::MOVE_RESULT:
     case Instruction::MOVE_RESULT_OBJECT:
-    case Instruction::INSTANCE_OF:
       // 1 result, treat as unique each time, use result s_reg - will be unique.
       res = GetOperandValue(mir->ssa_rep->defs[0]);
       SetOperandValue(mir->ssa_rep->defs[0], res);