ART: Refactor SsaBuilder for more precise typing info

This patch refactors the SsaBuilder to do the following:

1) All phis are constructed live and marked dead if not used or proved
to be conflicting.

2) Primitive type propagation, now not a separate pass, identifies
conflicting types and marks corresponding phis dead.

3) When compiling --debuggable, DeadPhiHandling used to revive phis
which had only environmental uses but did not attempt to resolve
conflicts. This pass was removed as obsolete and is now superseded
by primitive type propagation (identifying conflicting phis) and
SsaDeadPhiEliminiation (keeping phis live if debuggable + env use).

4) Resolving conflicts requires correct primitive type information
on all instructions. This was not the case for ArrayGet instructions
which can have ambiguous types in the bytecode. To this end,
SsaBuilder now runs reference type propagation and types ArrayGets
from the type of the input array.

5) With RTP being run inside the SsaBuilder, it is not necessary to
run it as a separate optimization pass. Optimizations can now assume
that all instructions of type kPrimNot have reference type info after
SsaBuilder (with the exception of NullConstant).

6) Graph now contains a reference type to be assigned to NullConstant.
All reference type instructions therefore have RTI, as now enforced
by the SsaChecker.

Bug: 24252151
Bug: 24252100
Bug: 22538329
Bug: 25786318

Change-Id: I7a3aee1ff66c82d64b4846611c547af17e91d260
diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc
index a4dcb3a..db11709 100644
--- a/compiler/optimizing/inliner.cc
+++ b/compiler/optimizing/inliner.cc
@@ -33,6 +33,7 @@
 #include "reference_type_propagation.h"
 #include "register_allocator.h"
 #include "sharpening.h"
+#include "ssa_builder.h"
 #include "ssa_phi_elimination.h"
 #include "scoped_thread_state_change.h"
 #include "thread.h"
@@ -514,7 +515,7 @@
     return false;
   }
 
-  if (!callee_graph->TryBuildingSsa()) {
+  if (callee_graph->TryBuildingSsa(handles_) != kBuildSsaSuccess) {
     VLOG(compiler) << "Method " << PrettyMethod(method_index, callee_dex_file)
                    << " could not be transformed to SSA";
     return false;
@@ -549,14 +550,12 @@
   // Run simple optimizations on the graph.
   HDeadCodeElimination dce(callee_graph, stats_);
   HConstantFolding fold(callee_graph);
-  ReferenceTypePropagation type_propagation(callee_graph, handles_);
   HSharpening sharpening(callee_graph, codegen_, dex_compilation_unit, compiler_driver_);
   InstructionSimplifier simplify(callee_graph, stats_);
   IntrinsicsRecognizer intrinsics(callee_graph, compiler_driver_);
 
   HOptimization* optimizations[] = {
     &intrinsics,
-    &type_propagation,
     &sharpening,
     &simplify,
     &fold,
@@ -677,42 +676,36 @@
     DCHECK_EQ(graph_, return_replacement->GetBlock()->GetGraph());
   }
 
-  // When merging the graph we might create a new NullConstant in the caller graph which does
-  // not have the chance to be typed. We assign the correct type here so that we can keep the
-  // assertion that every reference has a valid type. This also simplifies checks along the way.
-  HNullConstant* null_constant = graph_->GetNullConstant();
-  if (!null_constant->GetReferenceTypeInfo().IsValid()) {
-    ReferenceTypeInfo::TypeHandle obj_handle =
-        handles_->NewHandle(class_linker->GetClassRoot(ClassLinker::kJavaLangObject));
-    null_constant->SetReferenceTypeInfo(
-        ReferenceTypeInfo::Create(obj_handle, false /* is_exact */));
-  }
-
   // Check the integrity of reference types and run another type propagation if needed.
-  if ((return_replacement != nullptr)
-      && (return_replacement->GetType() == Primitive::kPrimNot)) {
-    if (!return_replacement->GetReferenceTypeInfo().IsValid()) {
-      // Make sure that we have a valid type for the return. We may get an invalid one when
-      // we inline invokes with multiple branches and create a Phi for the result.
-      // TODO: we could be more precise by merging the phi inputs but that requires
-      // some functionality from the reference type propagation.
-      DCHECK(return_replacement->IsPhi());
-      size_t pointer_size = Runtime::Current()->GetClassLinker()->GetImagePointerSize();
-      ReferenceTypeInfo::TypeHandle return_handle =
-          handles_->NewHandle(resolved_method->GetReturnType(true /* resolve */, pointer_size));
-      return_replacement->SetReferenceTypeInfo(ReferenceTypeInfo::Create(
-         return_handle, return_handle->CannotBeAssignedFromOtherTypes() /* is_exact */));
-    }
+  if (return_replacement != nullptr) {
+    if (return_replacement->GetType() == Primitive::kPrimNot) {
+      if (!return_replacement->GetReferenceTypeInfo().IsValid()) {
+        // Make sure that we have a valid type for the return. We may get an invalid one when
+        // we inline invokes with multiple branches and create a Phi for the result.
+        // TODO: we could be more precise by merging the phi inputs but that requires
+        // some functionality from the reference type propagation.
+        DCHECK(return_replacement->IsPhi());
+        size_t pointer_size = Runtime::Current()->GetClassLinker()->GetImagePointerSize();
+        ReferenceTypeInfo::TypeHandle return_handle =
+            handles_->NewHandle(resolved_method->GetReturnType(true /* resolve */, pointer_size));
+        return_replacement->SetReferenceTypeInfo(ReferenceTypeInfo::Create(
+            return_handle, return_handle->CannotBeAssignedFromOtherTypes() /* is_exact */));
+      }
 
-    if (do_rtp) {
-      // If the return type is a refinement of the declared type run the type propagation again.
-      ReferenceTypeInfo return_rti = return_replacement->GetReferenceTypeInfo();
-      ReferenceTypeInfo invoke_rti = invoke_instruction->GetReferenceTypeInfo();
-      if (invoke_rti.IsStrictSupertypeOf(return_rti)
-          || (return_rti.IsExact() && !invoke_rti.IsExact())
-          || !return_replacement->CanBeNull()) {
-        ReferenceTypePropagation rtp_fixup(graph_, handles_);
-        rtp_fixup.Run();
+      if (do_rtp) {
+        // If the return type is a refinement of the declared type run the type propagation again.
+        ReferenceTypeInfo return_rti = return_replacement->GetReferenceTypeInfo();
+        ReferenceTypeInfo invoke_rti = invoke_instruction->GetReferenceTypeInfo();
+        if (invoke_rti.IsStrictSupertypeOf(return_rti)
+            || (return_rti.IsExact() && !invoke_rti.IsExact())
+            || !return_replacement->CanBeNull()) {
+          ReferenceTypePropagation(graph_, handles_).Run();
+        }
+      }
+    } else if (return_replacement->IsInstanceOf()) {
+      if (do_rtp) {
+        // Inlining InstanceOf into an If may put a tighter bound on reference types.
+        ReferenceTypePropagation(graph_, handles_).Run();
       }
     }
   }