Use imprecise constants at compilation time.

During veriifcation, we create constant types for the following instructions:
const/4, const/16, const and const/high16. We used to create "precise" constant
types for each constant we process in the method being verified. Though precise
constants are only useful for deoptimization which happens at runtime.

This CL now creates "imprecise" constant types at compilation time. Since it
reduces the number of constant types we create during verification, it should
also reduce the amount of time spent in verification at compilation time.

Bug: 12167380
Bug: 12126841
Change-Id: I70522c4133a74a533fc2d2cb8d4f49888e590828
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index f03cdcd..9a2de47 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -1432,6 +1432,9 @@
   UniquePtr<RegisterLine> branch_line;
   UniquePtr<RegisterLine> fallthrough_line;
 
+  // We need precise constant types only for deoptimization which happens at runtime.
+  const bool need_precise_constant = !Runtime::Current()->IsCompiler();
+
   switch (inst->Opcode()) {
     case Instruction::NOP:
       /*
@@ -1582,22 +1585,28 @@
       /* could be boolean, int, float, or a null reference */
     case Instruction::CONST_4: {
       int32_t val = static_cast<int32_t>(inst->VRegB_11n() << 28) >> 28;
-      work_line_->SetRegisterType(inst->VRegA_11n(), reg_types_.FromCat1Const(val, true));
+      work_line_->SetRegisterType(inst->VRegA_11n(),
+                                  DetermineCat1Constant(val, need_precise_constant));
       break;
     }
     case Instruction::CONST_16: {
       int16_t val = static_cast<int16_t>(inst->VRegB_21s());
-      work_line_->SetRegisterType(inst->VRegA_21s(), reg_types_.FromCat1Const(val, true));
+      work_line_->SetRegisterType(inst->VRegA_21s(),
+                                  DetermineCat1Constant(val, need_precise_constant));
       break;
     }
-    case Instruction::CONST:
+    case Instruction::CONST: {
+      int32_t val = inst->VRegB_31i();
       work_line_->SetRegisterType(inst->VRegA_31i(),
-                                  reg_types_.FromCat1Const(inst->VRegB_31i(), true));
+                                  DetermineCat1Constant(val, need_precise_constant));
       break;
-    case Instruction::CONST_HIGH16:
+    }
+    case Instruction::CONST_HIGH16: {
+      int32_t val = static_cast<int32_t>(inst->VRegB_21h() << 16);
       work_line_->SetRegisterType(inst->VRegA_21h(),
-                                  reg_types_.FromCat1Const(inst->VRegB_21h() << 16, true));
+                                  DetermineCat1Constant(val, need_precise_constant));
       break;
+    }
       /* could be long or double; resolved upon use */
     case Instruction::CONST_WIDE_16: {
       int64_t val = static_cast<int16_t>(inst->VRegB_21s());
@@ -3928,6 +3937,34 @@
   return result;
 }
 
+const RegType& MethodVerifier::DetermineCat1Constant(int32_t value, bool precise) {
+  if (precise) {
+    // Precise constant type.
+    return reg_types_.FromCat1Const(value, true);
+  } else {
+    // Imprecise constant type.
+    if (value < -32768) {
+      return reg_types_.IntConstant();
+    } else if (value < -128) {
+      return reg_types_.ShortConstant();
+    } else if (value < 0) {
+      return reg_types_.ByteConstant();
+    } else if (value == 0) {
+      return reg_types_.Zero();
+    } else if (value == 1) {
+      return reg_types_.One();
+    } else if (value < 128) {
+      return reg_types_.PosByteConstant();
+    } else if (value < 32768) {
+      return reg_types_.PosShortConstant();
+    } else if (value < 65536) {
+      return reg_types_.CharConstant();
+    } else {
+      return reg_types_.IntConstant();
+    }
+  }
+}
+
 void MethodVerifier::Init() {
   art::verifier::RegTypeCache::Init();
 }