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/codegen.h b/src/compiler/codegen/codegen.h
index 9dfa609..06981568 100644
--- a/src/compiler/codegen/codegen.h
+++ b/src/compiler/codegen/codegen.h
@@ -381,6 +381,9 @@
     virtual void OpRegCopyWide(CompilationUnit* cu, int dest_lo, int dest_hi, int src_lo,
                                int src_hi) = 0;
     virtual void OpTlsCmp(CompilationUnit* cu, int offset, int val) = 0;
+
+    // Temp workaround
+    void Workaround7250540(CompilationUnit* cu, RegLocation rl_dest, int value);
     };  // Class Codegen
 
 }  // namespace art
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);
+    }
   }
 }
 
diff --git a/src/compiler/codegen/mir_to_gbc.cc b/src/compiler/codegen/mir_to_gbc.cc
index b5ad024..19b069c 100644
--- a/src/compiler/codegen/mir_to_gbc.cc
+++ b/src/compiler/codegen/mir_to_gbc.cc
@@ -2576,6 +2576,7 @@
   } else {
     cg->LoadConstantNoClobber(cu, rl_result.low_reg, immval & 0xffffffff);
     cg->StoreValue(cu, rl_dest, rl_result);
+    cg->Workaround7250540(cu, rl_dest, immval & 0xffffffff);
   }
 }
 
diff --git a/src/compiler/codegen/mir_to_lir.cc b/src/compiler/codegen/mir_to_lir.cc
index 5a6a5fc..3dc6d59 100644
--- a/src/compiler/codegen/mir_to_lir.cc
+++ b/src/compiler/codegen/mir_to_lir.cc
@@ -141,12 +141,14 @@
       rl_result = EvalLoc(cu, rl_dest, kAnyReg, true);
       cg->LoadConstantNoClobber(cu, rl_result.low_reg, vB);
       cg->StoreValue(cu, rl_dest, rl_result);
+      cg->Workaround7250540(cu, rl_dest, vB);
       break;
 
     case Instruction::CONST_HIGH16:
       rl_result = EvalLoc(cu, rl_dest, kAnyReg, true);
       cg->LoadConstantNoClobber(cu, rl_result.low_reg, vB << 16);
       cg->StoreValue(cu, rl_dest, rl_result);
+      cg->Workaround7250540(cu, rl_dest, vB);
       break;
 
     case Instruction::CONST_WIDE_16:
diff --git a/src/compiler/codegen/ralloc_util.cc b/src/compiler/codegen/ralloc_util.cc
index 7cc3fad..999c652 100644
--- a/src/compiler/codegen/ralloc_util.cc
+++ b/src/compiler/codegen/ralloc_util.cc
@@ -146,7 +146,7 @@
  * ssa name (above the last original Dalvik register).  This function
  * maps SSA names to positions in the promotion_map array.
  */
-static int SRegToPMap(CompilationUnit* cu, int s_reg)
+int SRegToPMap(CompilationUnit* cu, int s_reg)
 {
   DCHECK_LT(s_reg, cu->num_ssa_regs);
   DCHECK_GE(s_reg, 0);
diff --git a/src/compiler/codegen/ralloc_util.h b/src/compiler/codegen/ralloc_util.h
index 78a623b..3526f4c 100644
--- a/src/compiler/codegen/ralloc_util.h
+++ b/src/compiler/codegen/ralloc_util.h
@@ -156,6 +156,7 @@
 void RecordCorePromotion(CompilationUnit* cu, int reg, int s_reg);
 void RecordFpPromotion(CompilationUnit* cu, int reg, int s_reg);
 int ComputeFrameSize(CompilationUnit* cu);
+int SRegToPMap(CompilationUnit* cu, int s_reg);
 
 }  // namespace art
 
diff --git a/src/compiler/frontend.cc b/src/compiler/frontend.cc
index b8c9b8e..cd07dde 100644
--- a/src/compiler/frontend.cc
+++ b/src/compiler/frontend.cc
@@ -835,28 +835,6 @@
   }
 #endif
 
-#if 1
-// *** Temporary ****
-// For use in debugging issue 7250540.  Disable optimization in problem method
-// to see if monkey results change.  Should be removed after monkey runs
-// complete.
-if (PrettyMethod(method_idx, dex_file).find("void com.android.inputmethod.keyboard.Key.<init>(android.content.res.Resources, com.android.inputmethod.keyboard.Keyboard$Params, com.android.inputmethod.keyboard.Keyboard$Builder$Row, org.xmlpull.v1.XmlPullParser)") != std::string::npos) {
-    cu->disable_opt |= (
-        (1 << kLoadStoreElimination) |
-        (1 << kLoadHoisting) |
-        (1 << kSuppressLoads) |
-        //(1 << kNullCheckElimination) |
-        //(1 << kPromoteRegs) |
-        (1 << kTrackLiveTemps) |
-        //(1 << kSkipLargeMethodOptimization) |
-        //(1 << kSafeOptimizations) |
-        (1 << kBBOpt) |
-        (1 << kMatch) |
-        //(1 << kPromoteCompilerTemps) |
-        0);
-}
-#endif
-
   if (cu->instruction_set == kMips) {
     // Disable some optimizations for mips for now
     cu->disable_opt |= (