[optimizing] Add if-context sensitivity for null popagation.

Change-Id: I3725b6c6a6cf44440c34a1bfb67e623531e665d6
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index 352403d..ba01c2b 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -1002,6 +1002,8 @@
   virtual bool CanThrow() const { return false; }
   bool HasSideEffects() const { return side_effects_.HasSideEffects(); }
 
+  virtual bool ActAsNullConstant() const { return false; }
+
   // Does not apply for all instructions, but having this at top level greatly
   // simplifies the null check elimination.
   virtual bool CanBeNull() const {
@@ -1012,10 +1014,14 @@
   virtual bool CanDoImplicitNullCheck() const { return false; }
 
   void SetReferenceTypeInfo(ReferenceTypeInfo reference_type_info) {
+    DCHECK_EQ(GetType(), Primitive::kPrimNot);
     reference_type_info_ = reference_type_info;
   }
 
-  ReferenceTypeInfo GetReferenceTypeInfo() const { return reference_type_info_; }
+  ReferenceTypeInfo GetReferenceTypeInfo() const {
+    DCHECK_EQ(GetType(), Primitive::kPrimNot);
+    return reference_type_info_;
+  }
 
   void AddUseAt(HInstruction* user, size_t index) {
     uses_.AddUse(user, index, GetBlock()->GetGraph()->GetArena());
@@ -1787,6 +1793,8 @@
 
   size_t ComputeHashCode() const OVERRIDE { return 0; }
 
+  bool ActAsNullConstant() const OVERRIDE { return true; }
+
   DECLARE_INSTRUCTION(NullConstant);
 
  private:
@@ -1801,11 +1809,16 @@
 
   int32_t GetValue() const { return value_; }
 
-  virtual bool InstructionDataEquals(HInstruction* other) const {
+  bool InstructionDataEquals(HInstruction* other) const OVERRIDE {
     return other->AsIntConstant()->value_ == value_;
   }
 
-  virtual size_t ComputeHashCode() const { return GetValue(); }
+  size_t ComputeHashCode() const OVERRIDE { return GetValue(); }
+
+  // TODO: Null is represented by the `0` constant. In most cases we replace it
+  // with a HNullConstant but we don't do it when comparing (a != null). This
+  // method is an workaround until we fix the above.
+  bool ActAsNullConstant() const OVERRIDE { return value_ == 0; }
 
   DECLARE_INSTRUCTION(IntConstant);
 
@@ -3010,6 +3023,7 @@
   HBoundType(HInstruction* input, ReferenceTypeInfo bound_type)
       : HExpression(Primitive::kPrimNot, SideEffects::None()),
         bound_type_(bound_type) {
+    DCHECK_EQ(input->GetType(), Primitive::kPrimNot);
     SetRawInputAt(0, input);
   }
 
diff --git a/compiler/optimizing/reference_type_propagation.cc b/compiler/optimizing/reference_type_propagation.cc
index 76b8d7e..479b87f 100644
--- a/compiler/optimizing/reference_type_propagation.cc
+++ b/compiler/optimizing/reference_type_propagation.cc
@@ -23,8 +23,6 @@
 
 namespace art {
 
-// TODO: handle: a !=/== null.
-
 void ReferenceTypePropagation::Run() {
   // To properly propagate type info we need to visit in the dominator-based order.
   // Reverse post order guarantees a node's dominators are visited first.
@@ -55,9 +53,46 @@
   }
 
   // Add extra nodes to bound types.
+  BoundTypeForIfNotNull(block);
   BoundTypeForIfInstanceOf(block);
 }
 
+void ReferenceTypePropagation::BoundTypeForIfNotNull(HBasicBlock* block) {
+  HInstruction* lastInstruction = block->GetLastInstruction();
+  if (!lastInstruction->IsIf()) {
+    return;
+  }
+  HInstruction* ifInput = lastInstruction->InputAt(0);
+  if (!ifInput->IsNotEqual() && !ifInput->IsEqual()) {
+    return;
+  }
+  HInstruction* input0 = ifInput->InputAt(0);
+  HInstruction* input1 = ifInput->InputAt(1);
+  HInstruction* obj;
+
+  if ((input0->GetType() == Primitive::kPrimNot) && input1->ActAsNullConstant()) {
+    obj = input0;
+  } else if ((input1->GetType() == Primitive::kPrimNot) && input0->ActAsNullConstant()) {
+    obj = input1;
+  } else {
+    return;
+  }
+
+  HBoundType* bound_type =
+      new (graph_->GetArena()) HBoundType(obj, ReferenceTypeInfo::CreateTop(false));
+
+  block->InsertInstructionBefore(bound_type, lastInstruction);
+  HBasicBlock* notNullBlock = ifInput->IsNotEqual()
+      ? lastInstruction->AsIf()->IfTrueSuccessor()
+      : lastInstruction->AsIf()->IfFalseSuccessor();
+  for (HUseIterator<HInstruction*> it(obj->GetUses()); !it.Done(); it.Advance()) {
+    HInstruction* user = it.Current()->GetUser();
+    if (notNullBlock->Dominates(user->GetBlock())) {
+      user->ReplaceInput(bound_type, it.Current()->GetIndex());
+    }
+  }
+}
+
 // Detects if `block` is the True block for the pattern
 // `if (x instanceof ClassX) { }`
 // If that's the case insert an HBoundType instruction to bound the type of `x`
diff --git a/compiler/optimizing/reference_type_propagation.h b/compiler/optimizing/reference_type_propagation.h
index e346dbf..815caab 100644
--- a/compiler/optimizing/reference_type_propagation.h
+++ b/compiler/optimizing/reference_type_propagation.h
@@ -51,6 +51,7 @@
   void UpdateBoundType(HBoundType* bound_type) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   void UpdatePhi(HPhi* phi) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
+  void BoundTypeForIfNotNull(HBasicBlock* block);
   void BoundTypeForIfInstanceOf(HBasicBlock* block);
 
   void ProcessWorklist();
diff --git a/test/444-checker-nce/src/Main.java b/test/444-checker-nce/src/Main.java
index 9fb9c46..656c791 100644
--- a/test/444-checker-nce/src/Main.java
+++ b/test/444-checker-nce/src/Main.java
@@ -214,6 +214,30 @@
     return m;
   }
 
+  // CHECK-START: Main Main.scopeIfNotNullRemove(Main) instruction_simplifier_after_types (before)
+  // CHECK:         NullCheck
+
+  // CHECK-START: Main Main.scopeIfNotNullRemove(Main) instruction_simplifier_after_types (after)
+  // CHECK-NOT:     NullCheck
+  public Main scopeIfNotNullRemove(Main m) {
+    if (m != null) {
+      return m.g();
+    }
+    return m;
+  }
+
+  // CHECK-START: Main Main.scopeIfKeep(Main) instruction_simplifier_after_types (before)
+  // CHECK:         NullCheck
+
+  // CHECK-START: Main Main.scopeIfKeep(Main) instruction_simplifier_after_types (after)
+  // CHECK:         NullCheck
+  public Main scopeIfKeep(Main m) {
+    if (m == null) {
+      m = new Main();
+    }
+    return m.g();
+  }
+
   public Main() {}
   public Main(int dummy) {}