Workaround for Issue 7250540

There's a problem (originating with Dalvik's failure to properly type constants) with
Dalvik vregs that are used in both reference and floating point situations.  In
particular, if a constant zero is used in a floating point context, the verifier in
some cases will treat it as a null pointer for the purposes generating the GC map.

If that vreg ends up promoted to a floating point value, the run-time value of that
vreg will not be found during garbage collection.  As a quick workaround, this
CL causes the compiler to detect this special case of an immediate zero being loaded
into a promoted floating point register and also store a zero in the core/ref identity
of that vreg.

Note, the CL also excludes references from store elimination.

Change-Id: I72f0a96744823ff9c5a2bd961a5e39ac4bbc707b
diff --git a/src/compiler/codegen/gen_loadstore.cc b/src/compiler/codegen/gen_loadstore.cc
index 7d28e1b..11b4a62 100644
--- a/src/compiler/codegen/gen_loadstore.cc
+++ b/src/compiler/codegen/gen_loadstore.cc
@@ -35,6 +35,29 @@
   return LoadConstantNoClobber(cu, r_dest, value);
 }
 
+/*
+ * Temporary workaround for Issue 7250540.  If we're loading a constant zero into a
+ * 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)
+{
+  if (rl_dest.fp && (value == 0)) {
+    int pmap_index = SRegToPMap(cu, rl_dest.s_reg_low);
+    if (cu->promotion_map[pmap_index].fp_location == kLocPhysReg) {
+      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);
+      } 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);
+      }
+    }
+  }
+}
+
 /* Load a word at base + displacement.  Displacement must be word multiple */
 LIR* Codegen::LoadWordDisp(CompilationUnit* cu, int rBase, int displacement, int r_dest)
 {
@@ -172,7 +195,10 @@
                   rl_dest.low_reg, kWord);
     MarkClean(cu, rl_dest);
     def_end = cu->last_lir_insn;
-    MarkDef(cu, rl_dest, def_start, def_end);
+    if (!rl_dest.ref) {
+      // Exclude references from store elimination
+      MarkDef(cu, rl_dest, def_start, def_end);
+    }
   }
 }