Fix quick mode bugs for Mips.

This patch enable quick mode for Mips and allows the emulator to boot.
However the emulator is still not 100% functional. It still have problems
launching some apps.

Change-Id: Id46a39a649a2fd431a9f13b06ecf34cbd1d20930
Signed-off-by: Douglas Leung <douglas@mips.com>
diff --git a/compiler/dex/quick/gen_common.cc b/compiler/dex/quick/gen_common.cc
index b00cbeb..04a23cf 100644
--- a/compiler/dex/quick/gen_common.cc
+++ b/compiler/dex/quick/gen_common.cc
@@ -749,11 +749,12 @@
     } else {
       GenSgetCall<4>(this, is_long_or_double, is_object, &field_info);
     }
+    // FIXME: pGetXXStatic always return an int or int64 regardless of rl_dest.fp.
     if (is_long_or_double) {
-      RegLocation rl_result = GetReturnWide(LocToRegClass(rl_dest));
+      RegLocation rl_result = GetReturnWide(kCoreReg);
       StoreValueWide(rl_dest, rl_result);
     } else {
-      RegLocation rl_result = GetReturn(LocToRegClass(rl_dest));
+      RegLocation rl_result = GetReturn(rl_dest.ref ? kRefReg : kCoreReg);
       StoreValue(rl_dest, rl_result);
     }
   }
diff --git a/compiler/dex/quick/gen_invoke.cc b/compiler/dex/quick/gen_invoke.cc
index 008ebfb..569c97f 100644
--- a/compiler/dex/quick/gen_invoke.cc
+++ b/compiler/dex/quick/gen_invoke.cc
@@ -153,13 +153,14 @@
                                            RegLocation arg0, bool safepoint_pc) {
   RegStorage r_tgt = CallHelperSetup(helper_offset);
   if (arg0.wide == 0) {
-    LoadValueDirectFixed(arg0, TargetReg(kArg0));
+    LoadValueDirectFixed(arg0, TargetReg(arg0.fp ? kFArg0 : kArg0));
   } else {
     RegStorage r_tmp;
     if (cu_->target64) {
       r_tmp = RegStorage::Solo64(TargetReg(kArg0).GetReg());
     } else {
-      r_tmp = RegStorage::MakeRegPair(TargetReg(kArg0), TargetReg(kArg1));
+      r_tmp = RegStorage::MakeRegPair(TargetReg(arg0.fp ? kFArg0 : kArg0),
+                                      TargetReg(arg0.fp ? kFArg1 : kArg1));
     }
     LoadValueDirectWideFixed(arg0, r_tmp);
   }
@@ -190,7 +191,12 @@
     if (cu_->target64) {
       r_tmp = RegStorage::Solo64(TargetReg(kArg1).GetReg());
     } else {
-      r_tmp = RegStorage::MakeRegPair(TargetReg(kArg1), TargetReg(kArg2));
+      if (cu_->instruction_set == kMips) {
+        // skip kArg1 for stack alignment.
+        r_tmp = RegStorage::MakeRegPair(TargetReg(kArg2), TargetReg(kArg3));
+      } else {
+        r_tmp = RegStorage::MakeRegPair(TargetReg(kArg1), TargetReg(kArg2));
+      }
     }
     LoadValueDirectWideFixed(arg1, r_tmp);
   }
@@ -304,7 +310,8 @@
         if (arg1.fp) {
           r_tmp = RegStorage::MakeRegPair(TargetReg(kFArg2), TargetReg(kFArg3));
         } else {
-          r_tmp = RegStorage::MakeRegPair(TargetReg(kArg1), TargetReg(kArg2));
+          // skip kArg1 for stack alignment.
+          r_tmp = RegStorage::MakeRegPair(TargetReg(kArg2), TargetReg(kArg3));
         }
         LoadValueDirectWideFixed(arg1, r_tmp);
       } else {
diff --git a/compiler/dex/quick/mips/codegen_mips.h b/compiler/dex/quick/mips/codegen_mips.h
index c0ad916..61a047d 100644
--- a/compiler/dex/quick/mips/codegen_mips.h
+++ b/compiler/dex/quick/mips/codegen_mips.h
@@ -50,6 +50,7 @@
     void MarkGCCard(RegStorage val_reg, RegStorage tgt_addr_reg);
 
     // Required for target - register utilities.
+    RegStorage Solo64ToPair64(RegStorage reg);
     RegStorage TargetReg(SpecialTargetRegister reg);
     RegStorage GetArgMappingToPhysicalReg(int arg_num);
     RegLocation GetReturnAlt();
@@ -181,10 +182,10 @@
 
     // TODO: collapse r_dest.
     LIR* LoadBaseDispBody(RegStorage r_base, int displacement, RegStorage r_dest,
-                          RegStorage r_dest_hi, OpSize size);
+                          OpSize size);
     // TODO: collapse r_src.
     LIR* StoreBaseDispBody(RegStorage r_base, int displacement, RegStorage r_src,
-                           RegStorage r_src_hi, OpSize size);
+                           OpSize size);
     void SpillCoreRegs();
     void UnSpillCoreRegs();
     static const MipsEncodingMap EncodingMap[kMipsLast];
diff --git a/compiler/dex/quick/mips/int_mips.cc b/compiler/dex/quick/mips/int_mips.cc
index 903a770..cd29e78 100644
--- a/compiler/dex/quick/mips/int_mips.cc
+++ b/compiler/dex/quick/mips/int_mips.cc
@@ -485,9 +485,11 @@
   int len_offset = mirror::Array::LengthOffset().Int32Value();
   int data_offset;
   RegLocation rl_result;
-  rl_array = LoadValue(rl_array, kCoreReg);
+  rl_array = LoadValue(rl_array, kRefReg);
   rl_index = LoadValue(rl_index, kCoreReg);
 
+  // FIXME: need to add support for rl_index.is_const.
+
   if (size == k64 || size == kDouble) {
     data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Int32Value();
   } else {
@@ -558,8 +560,11 @@
     data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Int32Value();
   }
 
-  rl_array = LoadValue(rl_array, kCoreReg);
+  rl_array = LoadValue(rl_array, kRefReg);
   rl_index = LoadValue(rl_index, kCoreReg);
+
+  // FIXME: need to add support for rl_index.is_const.
+
   RegStorage reg_ptr;
   bool allocated_reg_ptr_temp = false;
   if (IsTemp(rl_array.reg) && !card_mark) {
diff --git a/compiler/dex/quick/mips/mips_lir.h b/compiler/dex/quick/mips/mips_lir.h
index 5b2cb9d..495eb16 100644
--- a/compiler/dex/quick/mips/mips_lir.h
+++ b/compiler/dex/quick/mips/mips_lir.h
@@ -138,6 +138,10 @@
 #define ENCODE_MIPS_REG_HI           (1ULL << kMipsRegHI)
 #define ENCODE_MIPS_REG_LO           (1ULL << kMipsRegLO)
 
+// Set FR_BIT to 0
+// This bit determines how the CPU access FP registers.
+#define FR_BIT   0
+
 enum MipsNativeRegisterPool {
   rZERO = RegStorage::k32BitSolo | RegStorage::kCoreRegister |  0,
   rAT   = RegStorage::k32BitSolo | RegStorage::kCoreRegister |  1,
@@ -210,6 +214,26 @@
   rF30 = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 30,
   rF31 = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 31,
 #endif
+#if (FR_BIT == 0)
+  rD0  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint |  0,
+  rD1  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint |  2,
+  rD2  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint |  4,
+  rD3  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint |  6,
+  rD4  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint |  8,
+  rD5  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 10,
+  rD6  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 12,
+  rD7  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 14,
+#if 0  // TODO: expand resource mask to enable use of all MIPS fp registers.
+  rD8  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 16,
+  rD9  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 18,
+  rD10 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 20,
+  rD11 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 22,
+  rD12 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 24,
+  rD13 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 26,
+  rD14 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 28,
+  rD15 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 30,
+#endif
+#else
   rD0  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint |  0,
   rD1  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint |  1,
   rD2  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint |  2,
@@ -228,6 +252,7 @@
   rD14 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 14,
   rD15 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 15,
 #endif
+#endif
 };
 
 constexpr RegStorage rs_rZERO(RegStorage::kValid | rZERO);
diff --git a/compiler/dex/quick/mips/target_mips.cc b/compiler/dex/quick/mips/target_mips.cc
index 76b5243..1d02cf7 100644
--- a/compiler/dex/quick/mips/target_mips.cc
+++ b/compiler/dex/quick/mips/target_mips.cc
@@ -75,6 +75,13 @@
   return mips_loc_c_return_double;
 }
 
+// Convert k64BitSolo into k64BitPair
+RegStorage MipsMir2Lir::Solo64ToPair64(RegStorage reg) {
+    DCHECK(reg.IsDouble());
+    int reg_num = (reg.GetRegNum() & ~1) | RegStorage::kFloatingPoint;
+    return RegStorage(RegStorage::k64BitPair, reg_num, reg_num + 1);
+}
+
 // Return a target-dependent special register.
 RegStorage MipsMir2Lir::TargetReg(SpecialTargetRegister reg) {
   RegStorage res_reg;
@@ -123,7 +130,11 @@
 ResourceMask MipsMir2Lir::GetRegMaskCommon(const RegStorage& reg) const {
   return reg.IsDouble()
       /* Each double register is equal to a pair of single-precision FP registers */
+#if (FR_BIT == 0)
+      ? ResourceMask::TwoBits((reg.GetRegNum() & ~1) + kMipsFPReg0)
+#else
       ? ResourceMask::TwoBits(reg.GetRegNum() * 2 + kMipsFPReg0)
+#endif
       : ResourceMask::Bit(reg.IsSingle() ? reg.GetRegNum() + kMipsFPReg0 : reg.GetRegNum());
 }
 
@@ -443,7 +454,11 @@
   GrowableArray<RegisterInfo*>::Iterator it(&reg_pool_->sp_regs_);
   for (RegisterInfo* info = it.Next(); info != nullptr; info = it.Next()) {
     int sp_reg_num = info->GetReg().GetRegNum();
+#if (FR_BIT == 0)
+    int dp_reg_num = sp_reg_num & ~1;
+#else
     int dp_reg_num = sp_reg_num >> 1;
+#endif
     RegStorage dp_reg = RegStorage::Solo64(RegStorage::kFloatingPoint | dp_reg_num);
     RegisterInfo* dp_reg_info = GetRegInfo(dp_reg);
     // Double precision register's master storage should refer to itself.
@@ -462,7 +477,11 @@
   // TODO: adjust when we roll to hard float calling convention.
   reg_pool_->next_core_reg_ = 2;
   reg_pool_->next_sp_reg_ = 2;
+#if (FR_BIT == 0)
+  reg_pool_->next_dp_reg_ = 2;
+#else
   reg_pool_->next_dp_reg_ = 1;
+#endif
 }
 
 /*
@@ -531,8 +550,13 @@
 }
 
 RegisterClass MipsMir2Lir::RegClassForFieldLoadStore(OpSize size, bool is_volatile) {
-  // No support for 64-bit atomic load/store on mips.
-  DCHECK(size != k64 && size != kDouble);
+  if (UNLIKELY(is_volatile)) {
+    // On Mips, atomic 64-bit load/store requires an fp register.
+    // Smaller aligned load/store is atomic for both core and fp registers.
+    if (size == k64 || size == kDouble) {
+      return kFPReg;
+    }
+  }
   // TODO: Verify that both core and fp registers are suitable for smaller sizes.
   return RegClassBySize(size);
 }
diff --git a/compiler/dex/quick/mips/utility_mips.cc b/compiler/dex/quick/mips/utility_mips.cc
index b49f436..d28abbf 100644
--- a/compiler/dex/quick/mips/utility_mips.cc
+++ b/compiler/dex/quick/mips/utility_mips.cc
@@ -342,6 +342,10 @@
 
 LIR* MipsMir2Lir::LoadConstantWide(RegStorage r_dest, int64_t value) {
   LIR *res;
+  if (!r_dest.IsPair()) {
+    // Form 64-bit pair
+    r_dest = Solo64ToPair64(r_dest);
+  }
   res = LoadConstantNoClobber(r_dest.GetLow(), Low32Bits(value));
   LoadConstantNoClobber(r_dest.GetHigh(), High32Bits(value));
   return res;
@@ -448,7 +452,7 @@
 
 // FIXME: don't split r_dest into 2 containers.
 LIR* MipsMir2Lir::LoadBaseDispBody(RegStorage r_base, int displacement, RegStorage r_dest,
-                                   RegStorage r_dest_hi, OpSize size) {
+                                   OpSize size) {
 /*
  * Load value from base + displacement.  Optionally perform null check
  * on base (which must have an associated s_reg and MIR).  If not
@@ -462,23 +466,21 @@
   LIR *load2 = NULL;
   MipsOpCode opcode = kMipsNop;
   bool short_form = IS_SIMM16(displacement);
-  bool pair = false;
+  bool pair = r_dest.IsPair();
 
   switch (size) {
     case k64:
     case kDouble:
-      pair = true;
-      opcode = kMipsLw;
+      if (!pair) {
+        // Form 64-bit pair
+        r_dest = Solo64ToPair64(r_dest);
+        pair = 1;
+      }
       if (r_dest.IsFloat()) {
+        DCHECK_EQ(r_dest.GetLowReg(), r_dest.GetHighReg() - 1);
         opcode = kMipsFlwc1;
-        if (r_dest.IsDouble()) {
-          int reg_num = (r_dest.GetRegNum() << 1) | RegStorage::kFloatingPoint;
-          r_dest = RegStorage(RegStorage::k64BitSolo, reg_num, reg_num + 1);
-        } else {
-          DCHECK(r_dest_hi.IsFloat());
-          DCHECK_EQ(r_dest.GetReg(), r_dest_hi.GetReg() - 1);
-          r_dest_hi.SetReg(r_dest.GetReg() + 1);
-        }
+      } else {
+        opcode = kMipsLw;
       }
       short_form = IS_SIMM16_2WORD(displacement);
       DCHECK_EQ((displacement & 0x3), 0);
@@ -515,15 +517,15 @@
     if (!pair) {
       load = res = NewLIR3(opcode, r_dest.GetReg(), displacement, r_base.GetReg());
     } else {
-      load = res = NewLIR3(opcode, r_dest.GetReg(), displacement + LOWORD_OFFSET, r_base.GetReg());
-      load2 = NewLIR3(opcode, r_dest_hi.GetReg(), displacement + HIWORD_OFFSET, r_base.GetReg());
+      load = res = NewLIR3(opcode, r_dest.GetLowReg(), displacement + LOWORD_OFFSET, r_base.GetReg());
+      load2 = NewLIR3(opcode, r_dest.GetHighReg(), displacement + HIWORD_OFFSET, r_base.GetReg());
     }
   } else {
     if (pair) {
       RegStorage r_tmp = AllocTemp();
       res = OpRegRegImm(kOpAdd, r_tmp, r_base, displacement);
-      load = NewLIR3(opcode, r_dest.GetReg(), LOWORD_OFFSET, r_tmp.GetReg());
-      load2 = NewLIR3(opcode, r_dest_hi.GetReg(), HIWORD_OFFSET, r_tmp.GetReg());
+      load = NewLIR3(opcode, r_dest.GetLowReg(), LOWORD_OFFSET, r_tmp.GetReg());
+      load2 = NewLIR3(opcode, r_dest.GetHighReg(), HIWORD_OFFSET, r_tmp.GetReg());
       FreeTemp(r_tmp);
     } else {
       RegStorage r_tmp = (r_base == r_dest) ? AllocTemp() : r_dest;
@@ -557,11 +559,7 @@
     size = k32;
   }
   LIR* load;
-  if (size == k64 || size == kDouble) {
-    load = LoadBaseDispBody(r_base, displacement, r_dest.GetLow(), r_dest.GetHigh(), size);
-  } else {
-    load = LoadBaseDispBody(r_base, displacement, r_dest, RegStorage::InvalidReg(), size);
-  }
+  load = LoadBaseDispBody(r_base, displacement, r_dest, size);
 
   if (UNLIKELY(is_volatile == kVolatile)) {
     // Without context sensitive analysis, we must issue the most conservative barriers.
@@ -575,7 +573,7 @@
 
 // FIXME: don't split r_dest into 2 containers.
 LIR* MipsMir2Lir::StoreBaseDispBody(RegStorage r_base, int displacement,
-                                    RegStorage r_src, RegStorage r_src_hi, OpSize size) {
+                                    RegStorage r_src, OpSize size) {
   LIR *res;
   LIR *store = NULL;
   LIR *store2 = NULL;
@@ -586,17 +584,16 @@
   switch (size) {
     case k64:
     case kDouble:
-      opcode = kMipsSw;
+      if (!pair) {
+        // Form 64-bit pair
+        r_src = Solo64ToPair64(r_src);
+        pair = 1;
+      }
       if (r_src.IsFloat()) {
+        DCHECK_EQ(r_src.GetLowReg(), r_src.GetHighReg() - 1);
         opcode = kMipsFswc1;
-        if (r_src.IsDouble()) {
-          int reg_num = (r_src.GetRegNum() << 1) | RegStorage::kFloatingPoint;
-          r_src = RegStorage(RegStorage::k64BitPair, reg_num, reg_num + 1);
-        } else {
-          DCHECK(r_src_hi.IsFloat());
-          DCHECK_EQ(r_src.GetReg(), (r_src_hi.GetReg() - 1));
-          r_src_hi.SetReg(r_src.GetReg() + 1);
-        }
+      } else {
+        opcode = kMipsSw;
       }
       short_form = IS_SIMM16_2WORD(displacement);
       DCHECK_EQ((displacement & 0x3), 0);
@@ -628,8 +625,8 @@
     if (!pair) {
       store = res = NewLIR3(opcode, r_src.GetReg(), displacement, r_base.GetReg());
     } else {
-      store = res = NewLIR3(opcode, r_src.GetReg(), displacement + LOWORD_OFFSET, r_base.GetReg());
-      store2 = NewLIR3(opcode, r_src_hi.GetReg(), displacement + HIWORD_OFFSET, r_base.GetReg());
+      store = res = NewLIR3(opcode, r_src.GetLowReg(), displacement + LOWORD_OFFSET, r_base.GetReg());
+      store2 = NewLIR3(opcode, r_src.GetHighReg(), displacement + HIWORD_OFFSET, r_base.GetReg());
     }
   } else {
     RegStorage r_scratch = AllocTemp();
@@ -637,8 +634,8 @@
     if (!pair) {
       store =  NewLIR3(opcode, r_src.GetReg(), 0, r_scratch.GetReg());
     } else {
-      store =  NewLIR3(opcode, r_src.GetReg(), LOWORD_OFFSET, r_scratch.GetReg());
-      store2 = NewLIR3(opcode, r_src_hi.GetReg(), HIWORD_OFFSET, r_scratch.GetReg());
+      store =  NewLIR3(opcode, r_src.GetLowReg(), LOWORD_OFFSET, r_scratch.GetReg());
+      store2 = NewLIR3(opcode, r_src.GetHighReg(), HIWORD_OFFSET, r_scratch.GetReg());
     }
     FreeTemp(r_scratch);
   }
@@ -669,11 +666,7 @@
     size = k32;
   }
   LIR* store;
-  if (size == k64 || size == kDouble) {
-    store = StoreBaseDispBody(r_base, displacement, r_src.GetLow(), r_src.GetHigh(), size);
-  } else {
-    store = StoreBaseDispBody(r_base, displacement, r_src, RegStorage::InvalidReg(), size);
-  }
+  store = StoreBaseDispBody(r_base, displacement, r_src, size);
 
   if (UNLIKELY(is_volatile == kVolatile)) {
     // A load might follow the volatile store so insert a StoreLoad barrier.
diff --git a/compiler/dex/quick/ralloc_util.cc b/compiler/dex/quick/ralloc_util.cc
index 60eebe4..81dabd4 100644
--- a/compiler/dex/quick/ralloc_util.cc
+++ b/compiler/dex/quick/ralloc_util.cc
@@ -359,7 +359,13 @@
        * NOTE: "wideness" is an attribute of how the container is used, not its physical size.
        * The caller will set wideness as appropriate.
        */
-      info->SetIsWide(false);
+      if (info->IsWide()) {
+        RegisterInfo* partner = GetRegInfo(info->Partner());
+        DCHECK_EQ(info->GetReg().GetRegNum(), partner->Partner().GetRegNum());
+        DCHECK(partner->IsWide());
+        info->SetIsWide(false);
+        partner->SetIsWide(false);
+      }
       *next_temp = next + 1;
       return info->GetReg();
     }
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index de2960c..bf04a54 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -1130,8 +1130,8 @@
   }
 
   if (compiler_filter_string == nullptr) {
-    if (instruction_set == kMips) {
-      // TODO: fix compiler for Mips.
+    if (instruction_set == kMips64) {
+      // TODO: fix compiler for Mips64.
       compiler_filter_string = "interpret-only";
     } else if (image) {
       compiler_filter_string = "speed";
diff --git a/runtime/instruction_set.h b/runtime/instruction_set.h
index 96eeb8d..6e10a4c 100644
--- a/runtime/instruction_set.h
+++ b/runtime/instruction_set.h
@@ -33,7 +33,8 @@
   kThumb2,
   kX86,
   kX86_64,
-  kMips
+  kMips,
+  kMips64
 };
 std::ostream& operator<<(std::ostream& os, const InstructionSet& rhs);