Quick compiler: tighten null/0/0.0 workaround

Change 255389 worked around an issue with the compiler and
garbage collector being out of sync regarding the type of a Dalvik
register loaded with a constant 0 value.

The workaround was to detect the case of a constant 0 loaded
into a promoted floating point register, and then also store a
zero in the core/reference identity of that Dalvik vreg.

This CL tightens the workaround by ensuring that the additional
store is only performed in cases in which the promoted-to-float
Dalvik vreg is also used as a reference at some point in the
method.

Additionally, it improves the code sequence somewhat by reusing
the register loaded with zero for the subsequent store.  Further,
an unrelated enhancement is made to the floating point immediate
loading code.  For Arm, a few floating point constant values are
supported via vmov immediate.  However, 0.0 is not a bit pattern
that can be directly generated.  Previously, we would load 0.0 from
the method's literal pool.  In this CL we instead materialize +2
in a core register, and then emit an vsub reg,reg,reg to convert
it to +0.0. This saves a few bytes of code space, and avoids a
memory reference.

In the future, we'll want to have more info about the target
CPU's capabilities.  A vector exclusive or would likely be
better here.

Change-Id: Icacd85c86112c5355d35b536e2f7a41c0357682c
diff --git a/src/compiler/codegen/gen_loadstore.cc b/src/compiler/codegen/gen_loadstore.cc
index 11b4a62..fe08caa 100644
--- a/src/compiler/codegen/gen_loadstore.cc
+++ b/src/compiler/codegen/gen_loadstore.cc
@@ -40,19 +40,28 @@
  * promoted floating point register, also copy a zero into the int/ref identity of
  * that sreg.
  */
-void Codegen::Workaround7250540(CompilationUnit* cu, RegLocation rl_dest, int value)
+void Codegen::Workaround7250540(CompilationUnit* cu, RegLocation rl_dest, int zero_reg)
 {
-  if (rl_dest.fp && (value == 0)) {
+  if (rl_dest.fp) {
     int pmap_index = SRegToPMap(cu, rl_dest.s_reg_low);
     if (cu->promotion_map[pmap_index].fp_location == kLocPhysReg) {
+      // Now, determine if this vreg is ever used as a reference.  If not, we're done.
+      bool used_as_reference = false;
+      int base_vreg = SRegToVReg(cu, rl_dest.s_reg_low);
+      for (int i = 0; !used_as_reference && (i < cu->num_ssa_regs); i++) {
+        if (SRegToVReg(cu, cu->reg_location[i].s_reg_low) == base_vreg) {
+          used_as_reference |= cu->reg_location[i].ref;
+        }
+      }
+      if (!used_as_reference) {
+        return;
+      }
       if (cu->promotion_map[pmap_index].core_location == kLocPhysReg) {
         // Promoted - just copy in a zero
-        LoadConstant(cu, cu->promotion_map[pmap_index].core_reg, 0);
+        OpRegCopy(cu, cu->promotion_map[pmap_index].core_reg, zero_reg);
       } else {
         // Lives in the frame, need to store.
-        int temp_reg = AllocTemp(cu);
-        LoadConstant(cu, temp_reg, 0);
-        StoreBaseDisp(cu, TargetReg(kSp), SRegOffset(cu, rl_dest.s_reg_low), temp_reg, kWord);
+        StoreBaseDisp(cu, TargetReg(kSp), SRegOffset(cu, rl_dest.s_reg_low), zero_reg, kWord);
       }
     }
   }