Small optimization improvements.

- Tune CanBeNull for HBoundType.
- Remove LoadClass when we know the class is loaded.
- Tune CanBeNull for StringInit.

Change-Id: I564ed33a506d65e991a514342bdfd1610bed0cf5
diff --git a/compiler/optimizing/instruction_simplifier.cc b/compiler/optimizing/instruction_simplifier.cc
index 931a1c3..df6e550 100644
--- a/compiler/optimizing/instruction_simplifier.cc
+++ b/compiler/optimizing/instruction_simplifier.cc
@@ -238,12 +238,19 @@
   }
 
   bool outcome;
-  if (TypeCheckHasKnownOutcome(check_cast->InputAt(1)->AsLoadClass(), object, &outcome)) {
+  HLoadClass* load_class = check_cast->InputAt(1)->AsLoadClass();
+  if (TypeCheckHasKnownOutcome(load_class, object, &outcome)) {
     if (outcome) {
       check_cast->GetBlock()->RemoveInstruction(check_cast);
       if (stats_ != nullptr) {
         stats_->RecordStat(MethodCompilationStat::kRemovedCheckedCast);
       }
+      if (!load_class->HasUses()) {
+        // We cannot rely on DCE to remove the class because the `HLoadClass` thinks it can throw.
+        // However, here we know that it cannot because the checkcast was successfull, hence
+        // the class was already loaded.
+        load_class->GetBlock()->RemoveInstruction(load_class);
+      }
     } else {
       // Don't do anything for exceptional cases for now. Ideally we should remove
       // all instructions and blocks this instruction dominates.
@@ -268,7 +275,8 @@
   }
 
   bool outcome;
-  if (TypeCheckHasKnownOutcome(instruction->InputAt(1)->AsLoadClass(), object, &outcome)) {
+  HLoadClass* load_class = instruction->InputAt(1)->AsLoadClass();
+  if (TypeCheckHasKnownOutcome(load_class, object, &outcome)) {
     if (outcome && can_be_null) {
       // Type test will succeed, we just need a null test.
       HNotEqual* test = new (graph->GetArena()) HNotEqual(graph->GetNullConstant(), object);
@@ -280,6 +288,12 @@
     }
     RecordSimplification();
     instruction->GetBlock()->RemoveInstruction(instruction);
+    if (outcome && !load_class->HasUses()) {
+      // We cannot rely on DCE to remove the class because the `HLoadClass` thinks it can throw.
+      // However, here we know that it cannot because the instanceof check was successfull, hence
+      // the class was already loaded.
+      load_class->GetBlock()->RemoveInstruction(load_class);
+    }
   }
 }
 
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index dba9233..efb7089 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -3023,6 +3023,10 @@
     return false;
   }
 
+  bool CanBeNull() const OVERRIDE {
+    return return_type_ == Primitive::kPrimNot && !IsStringInit();
+  }
+
   InvokeType GetInvokeType() const { return invoke_type_; }
   bool IsRecursive() const { return is_recursive_; }
   bool NeedsDexCache() const OVERRIDE { return !IsRecursive(); }
diff --git a/compiler/optimizing/reference_type_propagation.cc b/compiler/optimizing/reference_type_propagation.cc
index d1c1134..1349df9 100644
--- a/compiler/optimizing/reference_type_propagation.cc
+++ b/compiler/optimizing/reference_type_propagation.cc
@@ -167,6 +167,9 @@
     bound_type->SetReferenceTypeInfo(
         ReferenceTypeInfo::Create(class_rti.GetTypeHandle(), /* is_exact */ false));
   }
+  if (upper_can_be_null) {
+    bound_type->SetCanBeNull(obj->CanBeNull());
+  }
   return bound_type;
 }
 
@@ -485,6 +488,10 @@
               true /* CheckCast succeeds for nulls. */);
           check_cast->GetBlock()->InsertInstructionAfter(bound_type, check_cast);
         } else {
+          // Update nullability of the existing bound type, which may not have known
+          // that its input was not null when it was being created.
+          bound_type = check_cast->GetNext()->AsBoundType();
+          bound_type->SetCanBeNull(obj->CanBeNull());
           // We already have a bound type on the position we would need to insert
           // the new one. The existing bound type should dominate all the users
           // (dchecked) so there's no need to continue.