Skip null check in MarkGCCard() for known non-null values.

Use GVN's knowledge of non-null values to set a new MIR flag
for IPUT/SPUT/APUT to skip the value null check.

Change-Id: I97a8d1447acb530c9bbbf7b362add366d1486ee1
diff --git a/compiler/dex/quick/arm/int_arm.cc b/compiler/dex/quick/arm/int_arm.cc
index cab039b..e38dbf5 100644
--- a/compiler/dex/quick/arm/int_arm.cc
+++ b/compiler/dex/quick/arm/int_arm.cc
@@ -872,7 +872,7 @@
 
   if (is_object && !mir_graph_->IsConstantNullRef(rl_new_value)) {
     // Mark card for object assuming new value is stored.
-    MarkGCCard(rl_new_value.reg, rl_object.reg);
+    MarkGCCard(0, rl_new_value.reg, rl_object.reg);
   }
 
   RegLocation rl_offset = LoadValue(rl_src_offset, kCoreReg);
@@ -1471,7 +1471,7 @@
     FreeTemp(reg_ptr);
   }
   if (card_mark) {
-    MarkGCCard(rl_src.reg, rl_array.reg);
+    MarkGCCard(opt_flags, rl_src.reg, rl_array.reg);
   }
 }
 
diff --git a/compiler/dex/quick/arm64/int_arm64.cc b/compiler/dex/quick/arm64/int_arm64.cc
index 0e00698..b12fc0a 100644
--- a/compiler/dex/quick/arm64/int_arm64.cc
+++ b/compiler/dex/quick/arm64/int_arm64.cc
@@ -758,7 +758,7 @@
 
   if (is_object && !mir_graph_->IsConstantNullRef(rl_new_value)) {
     // Mark card for object assuming new value is stored.
-    MarkGCCard(rl_new_value.reg, rl_object.reg);
+    MarkGCCard(0, rl_new_value.reg, rl_object.reg);
   }
 
   RegStorage r_ptr = AllocTempRef();
@@ -1281,7 +1281,7 @@
     FreeTemp(reg_ptr);
   }
   if (card_mark) {
-    MarkGCCard(rl_src.reg, rl_array.reg);
+    MarkGCCard(opt_flags, rl_src.reg, rl_array.reg);
   }
 }
 
diff --git a/compiler/dex/quick/codegen_util.cc b/compiler/dex/quick/codegen_util.cc
index 80cb535..1cde01e 100644
--- a/compiler/dex/quick/codegen_util.cc
+++ b/compiler/dex/quick/codegen_util.cc
@@ -314,13 +314,17 @@
   }
 }
 
-void Mir2Lir::MarkGCCard(RegStorage val_reg, RegStorage tgt_addr_reg) {
+void Mir2Lir::MarkGCCard(int opt_flags, RegStorage val_reg, RegStorage tgt_addr_reg) {
   DCHECK(val_reg.Valid());
   DCHECK_EQ(val_reg.Is64Bit(), cu_->target64);
-  LIR* branch_over = OpCmpImmBranch(kCondEq, val_reg, 0, nullptr);
-  UnconditionallyMarkGCCard(tgt_addr_reg);
-  LIR* target = NewLIR0(kPseudoTargetLabel);
-  branch_over->target = target;
+  if ((opt_flags & MIR_STORE_NON_NULL_VALUE) != 0) {
+    UnconditionallyMarkGCCard(tgt_addr_reg);
+  } else {
+    LIR* branch_over = OpCmpImmBranch(kCondEq, val_reg, 0, nullptr);
+    UnconditionallyMarkGCCard(tgt_addr_reg);
+    LIR* target = NewLIR0(kPseudoTargetLabel);
+    branch_over->target = target;
+  }
 }
 
 /* Dump instructions and constant pool contents */
diff --git a/compiler/dex/quick/gen_common.cc b/compiler/dex/quick/gen_common.cc
index 4dd24cb..d1b8b03 100644
--- a/compiler/dex/quick/gen_common.cc
+++ b/compiler/dex/quick/gen_common.cc
@@ -665,7 +665,7 @@
                     field_info.IsVolatile() ? kVolatile : kNotVolatile);
     }
     if (IsRef(size) && !mir_graph_->IsConstantNullRef(rl_src)) {
-      MarkGCCard(rl_src.reg, r_base);
+      MarkGCCard(mir->optimization_flags, rl_src.reg, r_base);
     }
     FreeTemp(r_base);
   } else {
@@ -940,7 +940,7 @@
     }
     MarkPossibleNullPointerExceptionAfter(opt_flags, store);
     if (IsRef(size) && !mir_graph_->IsConstantNullRef(rl_src)) {
-      MarkGCCard(rl_src.reg, rl_obj.reg);
+      MarkGCCard(opt_flags, rl_src.reg, rl_obj.reg);
     }
   } else {
     QuickEntrypointEnum target;
diff --git a/compiler/dex/quick/gen_invoke.cc b/compiler/dex/quick/gen_invoke.cc
index a7900ae..31b81bf 100755
--- a/compiler/dex/quick/gen_invoke.cc
+++ b/compiler/dex/quick/gen_invoke.cc
@@ -1668,7 +1668,7 @@
     GenMemBarrier(kAnyAny);
   }
   if (is_object) {
-    MarkGCCard(rl_value.reg, rl_object.reg);
+    MarkGCCard(0, rl_value.reg, rl_object.reg);
   }
   return true;
 }
diff --git a/compiler/dex/quick/mips/int_mips.cc b/compiler/dex/quick/mips/int_mips.cc
index fb47238..0778c3b 100644
--- a/compiler/dex/quick/mips/int_mips.cc
+++ b/compiler/dex/quick/mips/int_mips.cc
@@ -641,7 +641,7 @@
     FreeTemp(reg_ptr);
   }
   if (card_mark) {
-    MarkGCCard(rl_src.reg, rl_array.reg);
+    MarkGCCard(opt_flags, rl_src.reg, rl_array.reg);
   }
 }
 
diff --git a/compiler/dex/quick/mir_to_lir.cc b/compiler/dex/quick/mir_to_lir.cc
index 70ef991..0d30927 100644
--- a/compiler/dex/quick/mir_to_lir.cc
+++ b/compiler/dex/quick/mir_to_lir.cc
@@ -332,7 +332,7 @@
         kNotVolatile);
   }
   if (IsRef(size)) {
-    MarkGCCard(reg_src, reg_obj);
+    MarkGCCard(0, reg_src, reg_obj);
   }
   return true;
 }
diff --git a/compiler/dex/quick/mir_to_lir.h b/compiler/dex/quick/mir_to_lir.h
index 886b238..49b8452 100644
--- a/compiler/dex/quick/mir_to_lir.h
+++ b/compiler/dex/quick/mir_to_lir.h
@@ -1075,8 +1075,9 @@
      * @brief Mark a garbage collection card. Skip if the stored value is null.
      * @param val_reg the register holding the stored value to check against null.
      * @param tgt_addr_reg the address of the object or array where the value was stored.
+     * @param opt_flags the optimization flags which may indicate that the value is non-null.
      */
-    void MarkGCCard(RegStorage val_reg, RegStorage tgt_addr_reg);
+    void MarkGCCard(int opt_flags, RegStorage val_reg, RegStorage tgt_addr_reg);
 
     /*
      * @brief Load the address of the dex method into the register.
diff --git a/compiler/dex/quick/x86/int_x86.cc b/compiler/dex/quick/x86/int_x86.cc
index 3f501b4..74ae8a6 100755
--- a/compiler/dex/quick/x86/int_x86.cc
+++ b/compiler/dex/quick/x86/int_x86.cc
@@ -1170,7 +1170,7 @@
     if (is_object && !mir_graph_->IsConstantNullRef(rl_new_value)) {
       // Mark card for object assuming new value is stored.
       FreeTemp(rs_r0);  // Temporarily release EAX for MarkGCCard().
-      MarkGCCard(rl_new_value.reg, rl_object.reg);
+      MarkGCCard(0, rl_new_value.reg, rl_object.reg);
       LockTemp(rs_r0);
     }
 
@@ -2398,7 +2398,7 @@
     if (!constant_index) {
       FreeTemp(rl_index.reg);
     }
-    MarkGCCard(rl_src.reg, rl_array.reg);
+    MarkGCCard(opt_flags, rl_src.reg, rl_array.reg);
   }
 }