Revert "Revert "[MIPS] Use hard float calling convention for managed code""

This reverts commit 7fee84c087e0f903e7d43bef180df047db1c8051.

Fixed issue with temporary registers on Mips32r6.

Change-Id: I93018927e6a6036cff2d55e6cda66d3212a4316b
diff --git a/compiler/dex/quick/mips/codegen_mips.h b/compiler/dex/quick/mips/codegen_mips.h
index 43fbcbd..2173253 100644
--- a/compiler/dex/quick/mips/codegen_mips.h
+++ b/compiler/dex/quick/mips/codegen_mips.h
@@ -29,15 +29,18 @@
  protected:
   class InToRegStorageMipsMapper : public InToRegStorageMapper {
    public:
-    explicit InToRegStorageMipsMapper(Mir2Lir* m2l) : m2l_(m2l), cur_core_reg_(0) {}
+    explicit InToRegStorageMipsMapper(Mir2Lir* m2l) : m2l_(m2l), cur_core_reg_(0), cur_fpu_reg_(0)
+        {}
     virtual RegStorage GetNextReg(ShortyArg arg);
     virtual void Reset() OVERRIDE {
       cur_core_reg_ = 0;
+      cur_fpu_reg_ = 0;
     }
    protected:
     Mir2Lir* m2l_;
    private:
     size_t cur_core_reg_;
+    size_t cur_fpu_reg_;
   };
 
   class InToRegStorageMips64Mapper : public InToRegStorageMapper {
diff --git a/compiler/dex/quick/mips/target_mips.cc b/compiler/dex/quick/mips/target_mips.cc
index ec4bad7..09d37f8 100644
--- a/compiler/dex/quick/mips/target_mips.cc
+++ b/compiler/dex/quick/mips/target_mips.cc
@@ -195,7 +195,7 @@
 // Return a target-dependent special register.
 RegStorage MipsMir2Lir::TargetReg(SpecialTargetRegister reg, WideKind wide_kind) {
   if (!cu_->target64 && wide_kind == kWide) {
-    DCHECK((kArg0 <= reg && reg < kArg7) || (kFArg0 <= reg && reg < kFArg15) || (kRet0 == reg));
+    DCHECK((kArg0 <= reg && reg < kArg7) || (kFArg0 == reg) || (kFArg2 == reg) || (kRet0 == reg));
     RegStorage ret_reg = RegStorage::MakeRegPair(TargetReg(reg),
                                      TargetReg(static_cast<SpecialTargetRegister>(reg + 1)));
     if (!fpuIs32Bit_ && ret_reg.IsFloat()) {
@@ -250,14 +250,27 @@
 RegStorage MipsMir2Lir::InToRegStorageMipsMapper::GetNextReg(ShortyArg arg) {
   const SpecialTargetRegister coreArgMappingToPhysicalReg[] = {kArg1, kArg2, kArg3};
   const size_t coreArgMappingToPhysicalRegSize = arraysize(coreArgMappingToPhysicalReg);
+  const SpecialTargetRegister fpuArgMappingToPhysicalReg[] = {kFArg0, kFArg2};
+  const size_t fpuArgMappingToPhysicalRegSize = arraysize(fpuArgMappingToPhysicalReg);
 
   RegStorage result = RegStorage::InvalidReg();
-  if (cur_core_reg_ < coreArgMappingToPhysicalRegSize) {
-    result = m2l_->TargetReg(coreArgMappingToPhysicalReg[cur_core_reg_++],
-                             arg.IsRef() ? kRef : kNotWide);
-    if (arg.IsWide() && cur_core_reg_ < coreArgMappingToPhysicalRegSize) {
-      result = RegStorage::MakeRegPair(
-          result, m2l_->TargetReg(coreArgMappingToPhysicalReg[cur_core_reg_++], kNotWide));
+  if (arg.IsFP()) {
+    if (cur_fpu_reg_ < fpuArgMappingToPhysicalRegSize) {
+      result = m2l_->TargetReg(fpuArgMappingToPhysicalReg[cur_fpu_reg_++],
+                               arg.IsWide() ? kWide : kNotWide);
+    }
+  } else {
+    if (cur_core_reg_ < coreArgMappingToPhysicalRegSize) {
+      if (arg.IsWide() && cur_core_reg_ == 0) {
+        // Don't use a1-a2 as a register pair, move to a2-a3 instead.
+        cur_core_reg_++;
+      }
+      result = m2l_->TargetReg(coreArgMappingToPhysicalReg[cur_core_reg_++],
+                               arg.IsRef() ? kRef : kNotWide);
+      if (arg.IsWide() && cur_core_reg_ < coreArgMappingToPhysicalRegSize) {
+        result = RegStorage::MakeRegPair(
+            result, m2l_->TargetReg(coreArgMappingToPhysicalReg[cur_core_reg_++], kNotWide));
+      }
     }
   }
   return result;
@@ -654,6 +667,20 @@
     LockTemp(TargetReg(kArg5));
     LockTemp(TargetReg(kArg6));
     LockTemp(TargetReg(kArg7));
+  } else {
+    if (fpuIs32Bit_) {
+      LockTemp(TargetReg(kFArg0));
+      LockTemp(TargetReg(kFArg1));
+      LockTemp(TargetReg(kFArg2));
+      LockTemp(TargetReg(kFArg3));
+      LockTemp(rs_rD6_fr0);
+      LockTemp(rs_rD7_fr0);
+    } else {
+      LockTemp(TargetReg(kFArg0));
+      LockTemp(TargetReg(kFArg2));
+      LockTemp(rs_rD6_fr1);
+      LockTemp(rs_rD7_fr1);
+    }
   }
 }
 
@@ -668,6 +695,20 @@
     FreeTemp(TargetReg(kArg5));
     FreeTemp(TargetReg(kArg6));
     FreeTemp(TargetReg(kArg7));
+  } else {
+    if (fpuIs32Bit_) {
+      FreeTemp(TargetReg(kFArg0));
+      FreeTemp(TargetReg(kFArg1));
+      FreeTemp(TargetReg(kFArg2));
+      FreeTemp(TargetReg(kFArg3));
+      FreeTemp(rs_rD6_fr0);
+      FreeTemp(rs_rD7_fr0);
+    } else {
+      FreeTemp(TargetReg(kFArg0));
+      FreeTemp(TargetReg(kFArg2));
+      FreeTemp(rs_rD6_fr1);
+      FreeTemp(rs_rD7_fr1);
+    }
   }
   FreeTemp(TargetReg(kHiddenArg));
 }
diff --git a/compiler/jni/jni_cfi_test_expected.inc b/compiler/jni/jni_cfi_test_expected.inc
index dd4496f..8b5fdc3 100644
--- a/compiler/jni/jni_cfi_test_expected.inc
+++ b/compiler/jni/jni_cfi_test_expected.inc
@@ -329,17 +329,18 @@
     0x34, 0x00, 0xAF, 0xAF, 0x30, 0x00, 0xAE, 0xAF, 0x2C, 0x00, 0xAD, 0xAF,
     0x28, 0x00, 0xAC, 0xAF, 0x24, 0x00, 0xAB, 0xAF, 0x20, 0x00, 0xAA, 0xAF,
     0x1C, 0x00, 0xA9, 0xAF, 0x18, 0x00, 0xA8, 0xAF, 0x00, 0x00, 0xA4, 0xAF,
-    0x44, 0x00, 0xA5, 0xAF, 0x48, 0x00, 0xA6, 0xAF, 0x4C, 0x00, 0xA7, 0xAF,
-    0xE0, 0xFF, 0xBD, 0x27, 0x20, 0x00, 0xBD, 0x27, 0x18, 0x00, 0xA8, 0x8F,
-    0x1C, 0x00, 0xA9, 0x8F, 0x20, 0x00, 0xAA, 0x8F, 0x24, 0x00, 0xAB, 0x8F,
-    0x28, 0x00, 0xAC, 0x8F, 0x2C, 0x00, 0xAD, 0x8F, 0x30, 0x00, 0xAE, 0x8F,
-    0x34, 0x00, 0xAF, 0x8F, 0x38, 0x00, 0xB8, 0x8F, 0x3C, 0x00, 0xBF, 0x8F,
-    0x40, 0x00, 0xBD, 0x27, 0x09, 0x00, 0xE0, 0x03, 0x00, 0x00, 0x00, 0x00,
+    0x44, 0x00, 0xA5, 0xAF, 0x48, 0x00, 0xAC, 0xE7, 0x4C, 0x00, 0xA6, 0xAF,
+    0x50, 0x00, 0xA7, 0xAF, 0xE0, 0xFF, 0xBD, 0x27, 0x20, 0x00, 0xBD, 0x27,
+    0x18, 0x00, 0xA8, 0x8F, 0x1C, 0x00, 0xA9, 0x8F, 0x20, 0x00, 0xAA, 0x8F,
+    0x24, 0x00, 0xAB, 0x8F, 0x28, 0x00, 0xAC, 0x8F, 0x2C, 0x00, 0xAD, 0x8F,
+    0x30, 0x00, 0xAE, 0x8F, 0x34, 0x00, 0xAF, 0x8F, 0x38, 0x00, 0xB8, 0x8F,
+    0x3C, 0x00, 0xBF, 0x8F, 0x40, 0x00, 0xBD, 0x27, 0x09, 0x00, 0xE0, 0x03,
+    0x00, 0x00, 0x00, 0x00,
 };
 static constexpr uint8_t expected_cfi_kMips[] = {
     0x44, 0x0E, 0x40, 0x44, 0x9F, 0x01, 0x44, 0x98, 0x02, 0x44, 0x8F, 0x03,
     0x44, 0x8E, 0x04, 0x44, 0x8D, 0x05, 0x44, 0x8C, 0x06, 0x44, 0x8B, 0x07,
-    0x44, 0x8A, 0x08, 0x44, 0x89, 0x09, 0x44, 0x88, 0x0A, 0x54, 0x0E, 0x60,
+    0x44, 0x8A, 0x08, 0x44, 0x89, 0x09, 0x44, 0x88, 0x0A, 0x58, 0x0E, 0x60,
     0x44, 0x0E, 0x40, 0x0A, 0x44, 0xC8, 0x44, 0xC9, 0x44, 0xCA, 0x44, 0xCB,
     0x44, 0xCC, 0x44, 0xCD, 0x44, 0xCE, 0x44, 0xCF, 0x44, 0xD8, 0x44, 0xDF,
     0x44, 0x0E, 0x00, 0x48, 0x0B, 0x0E, 0x40,
@@ -368,39 +369,40 @@
 // 0x0000002c: .cfi_offset: r8 at cfa-40
 // 0x0000002c: sw r4, +0(r29)
 // 0x00000030: sw r5, +68(r29)
-// 0x00000034: sw r6, +72(r29)
-// 0x00000038: sw r7, +76(r29)
-// 0x0000003c: addiu r29, r29, -32
-// 0x00000040: .cfi_def_cfa_offset: 96
-// 0x00000040: addiu r29, r29, 32
-// 0x00000044: .cfi_def_cfa_offset: 64
-// 0x00000044: .cfi_remember_state
-// 0x00000044: lw r8, +24(r29)
-// 0x00000048: .cfi_restore: r8
-// 0x00000048: lw r9, +28(r29)
-// 0x0000004c: .cfi_restore: r9
-// 0x0000004c: lw r10, +32(r29)
-// 0x00000050: .cfi_restore: r10
-// 0x00000050: lw r11, +36(r29)
-// 0x00000054: .cfi_restore: r11
-// 0x00000054: lw r12, +40(r29)
-// 0x00000058: .cfi_restore: r12
-// 0x00000058: lw r13, +44(r29)
-// 0x0000005c: .cfi_restore: r13
-// 0x0000005c: lw r14, +48(r29)
-// 0x00000060: .cfi_restore: r14
-// 0x00000060: lw r15, +52(r29)
-// 0x00000064: .cfi_restore: r15
-// 0x00000064: lw r24, +56(r29)
-// 0x00000068: .cfi_restore: r24
-// 0x00000068: lw r31, +60(r29)
-// 0x0000006c: .cfi_restore: r31
-// 0x0000006c: addiu r29, r29, 64
-// 0x00000070: .cfi_def_cfa_offset: 0
-// 0x00000070: jr r31
-// 0x00000074: nop
-// 0x00000078: .cfi_restore_state
-// 0x00000078: .cfi_def_cfa_offset: 64
+// 0x00000034: swc1 f12, +72(r29)
+// 0x00000038: sw r6, +76(r29)
+// 0x0000003c: sw r7, +80(r29)
+// 0x00000040: addiu r29, r29, -32
+// 0x00000044: .cfi_def_cfa_offset: 96
+// 0x00000044: addiu r29, r29, 32
+// 0x00000048: .cfi_def_cfa_offset: 64
+// 0x00000048: .cfi_remember_state
+// 0x00000048: lw r8, +24(r29)
+// 0x0000004c: .cfi_restore: r8
+// 0x0000004c: lw r9, +28(r29)
+// 0x00000050: .cfi_restore: r9
+// 0x00000050: lw r10, +32(r29)
+// 0x00000054: .cfi_restore: r10
+// 0x00000054: lw r11, +36(r29)
+// 0x00000058: .cfi_restore: r11
+// 0x00000058: lw r12, +40(r29)
+// 0x0000005c: .cfi_restore: r12
+// 0x0000005c: lw r13, +44(r29)
+// 0x00000060: .cfi_restore: r13
+// 0x00000060: lw r14, +48(r29)
+// 0x00000064: .cfi_restore: r14
+// 0x00000064: lw r15, +52(r29)
+// 0x00000068: .cfi_restore: r15
+// 0x00000068: lw r24, +56(r29)
+// 0x0000006c: .cfi_restore: r24
+// 0x0000006c: lw r31, +60(r29)
+// 0x00000070: .cfi_restore: r31
+// 0x00000070: addiu r29, r29, 64
+// 0x00000074: .cfi_def_cfa_offset: 0
+// 0x00000074: jr r31
+// 0x00000078: nop
+// 0x0000007c: .cfi_restore_state
+// 0x0000007c: .cfi_def_cfa_offset: 64
 
 static constexpr uint8_t expected_asm_kMips64[] = {
     0xA0, 0xFF, 0xBD, 0x67, 0x58, 0x00, 0xBF, 0xFF, 0x50, 0x00, 0xBE, 0xFF,
diff --git a/compiler/jni/quick/mips/calling_convention_mips.cc b/compiler/jni/quick/mips/calling_convention_mips.cc
index 4e716b5..be2397f 100644
--- a/compiler/jni/quick/mips/calling_convention_mips.cc
+++ b/compiler/jni/quick/mips/calling_convention_mips.cc
@@ -23,6 +23,10 @@
 namespace art {
 namespace mips {
 
+static const Register kCoreArgumentRegisters[] = { A0, A1, A2, A3 };
+static const FRegister kFArgumentRegisters[] = { F12, F14 };
+static const DRegister kDArgumentRegisters[] = { D6, D7 };
+
 // Calling convention
 ManagedRegister MipsManagedRuntimeCallingConvention::InterproceduralScratchRegister() {
   return MipsManagedRegister::FromCoreRegister(T9);
@@ -89,14 +93,49 @@
 const ManagedRegisterEntrySpills& MipsManagedRuntimeCallingConvention::EntrySpills() {
   // We spill the argument registers on MIPS to free them up for scratch use, we then assume
   // all arguments are on the stack.
-  if (entry_spills_.size() == 0) {
-    size_t num_spills = NumArgs() + NumLongOrDoubleArgs();
-    if (num_spills > 0) {
-      entry_spills_.push_back(MipsManagedRegister::FromCoreRegister(A1));
-      if (num_spills > 1) {
-        entry_spills_.push_back(MipsManagedRegister::FromCoreRegister(A2));
-        if (num_spills > 2) {
-          entry_spills_.push_back(MipsManagedRegister::FromCoreRegister(A3));
+  if ((entry_spills_.size() == 0) && (NumArgs() > 0)) {
+    uint32_t gpr_index = 1;  // Skip A0, it is used for ArtMethod*.
+    uint32_t fpr_index = 0;
+
+    for (ResetIterator(FrameOffset(0)); HasNext(); Next()) {
+      if (IsCurrentParamAFloatOrDouble()) {
+        if (IsCurrentParamADouble()) {
+          if (fpr_index < arraysize(kDArgumentRegisters)) {
+            entry_spills_.push_back(
+                MipsManagedRegister::FromDRegister(kDArgumentRegisters[fpr_index++]));
+          } else {
+            entry_spills_.push_back(ManagedRegister::NoRegister(), 8);
+          }
+        } else {
+          if (fpr_index < arraysize(kFArgumentRegisters)) {
+            entry_spills_.push_back(
+                MipsManagedRegister::FromFRegister(kFArgumentRegisters[fpr_index++]));
+          } else {
+            entry_spills_.push_back(ManagedRegister::NoRegister(), 4);
+          }
+        }
+      } else {
+        if (IsCurrentParamALong() && !IsCurrentParamAReference()) {
+          if (gpr_index == 1) {
+            // Don't use a1-a2 as a register pair, move to a2-a3 instead.
+            gpr_index++;
+          }
+          if (gpr_index < arraysize(kCoreArgumentRegisters) - 1) {
+            entry_spills_.push_back(
+                MipsManagedRegister::FromCoreRegister(kCoreArgumentRegisters[gpr_index++]));
+          } else if (gpr_index == arraysize(kCoreArgumentRegisters) - 1) {
+            gpr_index++;
+            entry_spills_.push_back(ManagedRegister::NoRegister(), 4);
+          } else {
+            entry_spills_.push_back(ManagedRegister::NoRegister(), 4);
+          }
+        }
+
+        if (gpr_index < arraysize(kCoreArgumentRegisters)) {
+          entry_spills_.push_back(
+            MipsManagedRegister::FromCoreRegister(kCoreArgumentRegisters[gpr_index++]));
+        } else {
+          entry_spills_.push_back(ManagedRegister::NoRegister(), 4);
         }
       }
     }
diff --git a/compiler/utils/mips/assembler_mips.cc b/compiler/utils/mips/assembler_mips.cc
index c09dfcc..c5fae92 100644
--- a/compiler/utils/mips/assembler_mips.cc
+++ b/compiler/utils/mips/assembler_mips.cc
@@ -359,23 +359,19 @@
 }
 
 void MipsAssembler::AddD(DRegister fd, DRegister fs, DRegister ft) {
-  EmitFR(0x11, 0x11, static_cast<FRegister>(ft), static_cast<FRegister>(fs),
-         static_cast<FRegister>(fd), 0x0);
+  EmitFR(0x11, 0x11, ConvertDRegToFReg(ft), ConvertDRegToFReg(fs), ConvertDRegToFReg(fd), 0x0);
 }
 
 void MipsAssembler::SubD(DRegister fd, DRegister fs, DRegister ft) {
-  EmitFR(0x11, 0x11, static_cast<FRegister>(ft), static_cast<FRegister>(fs),
-         static_cast<FRegister>(fd), 0x1);
+  EmitFR(0x11, 0x11, ConvertDRegToFReg(ft), ConvertDRegToFReg(fs), ConvertDRegToFReg(fd), 0x1);
 }
 
 void MipsAssembler::MulD(DRegister fd, DRegister fs, DRegister ft) {
-  EmitFR(0x11, 0x11, static_cast<FRegister>(ft), static_cast<FRegister>(fs),
-         static_cast<FRegister>(fd), 0x2);
+  EmitFR(0x11, 0x11, ConvertDRegToFReg(ft), ConvertDRegToFReg(fs), ConvertDRegToFReg(fd), 0x2);
 }
 
 void MipsAssembler::DivD(DRegister fd, DRegister fs, DRegister ft) {
-  EmitFR(0x11, 0x11, static_cast<FRegister>(ft), static_cast<FRegister>(fs),
-         static_cast<FRegister>(fd), 0x3);
+  EmitFR(0x11, 0x11, ConvertDRegToFReg(ft), ConvertDRegToFReg(fs), ConvertDRegToFReg(fd), 0x3);
 }
 
 void MipsAssembler::MovS(FRegister fd, FRegister fs) {
@@ -383,32 +379,31 @@
 }
 
 void MipsAssembler::MovD(DRegister fd, DRegister fs) {
-  EmitFR(0x11, 0x11, static_cast<FRegister>(0), static_cast<FRegister>(fs),
-         static_cast<FRegister>(fd), 0x6);
+  EmitFR(0x11, 0x11, static_cast<FRegister>(0), ConvertDRegToFReg(fs), ConvertDRegToFReg(fd), 0x6);
 }
 
 void MipsAssembler::Mfc1(Register rt, FRegister fs) {
-  EmitFR(0x11, 0x00, static_cast<FRegister>(rt), fs, static_cast<FRegister>(0), 0x0);
+  EmitFR(0x11, 0x00, ConvertRegToFReg(rt), fs, static_cast<FRegister>(0), 0x0);
 }
 
 void MipsAssembler::Mtc1(FRegister ft, Register rs) {
-  EmitFR(0x11, 0x04, ft, static_cast<FRegister>(rs), static_cast<FRegister>(0), 0x0);
+  EmitFR(0x11, 0x04, ft, ConvertRegToFReg(rs), static_cast<FRegister>(0), 0x0);
 }
 
 void MipsAssembler::Lwc1(FRegister ft, Register rs, uint16_t imm16) {
-  EmitI(0x31, rs, static_cast<Register>(ft), imm16);
+  EmitI(0x31, rs, ConvertFRegToReg(ft), imm16);
 }
 
 void MipsAssembler::Ldc1(DRegister ft, Register rs, uint16_t imm16) {
-  EmitI(0x35, rs, static_cast<Register>(ft), imm16);
+  EmitI(0x35, rs, ConvertDRegToReg(ft), imm16);
 }
 
 void MipsAssembler::Swc1(FRegister ft, Register rs, uint16_t imm16) {
-  EmitI(0x39, rs, static_cast<Register>(ft), imm16);
+  EmitI(0x39, rs, ConvertFRegToReg(ft), imm16);
 }
 
 void MipsAssembler::Sdc1(DRegister ft, Register rs, uint16_t imm16) {
-  EmitI(0x3d, rs, static_cast<Register>(ft), imm16);
+  EmitI(0x3d, rs, ConvertDRegToReg(ft), imm16);
 }
 
 void MipsAssembler::Break() {
@@ -529,7 +524,7 @@
   }
 }
 
-void MipsAssembler::StoreFToOffset(FRegister reg, Register base, int32_t offset) {
+void MipsAssembler::StoreSToOffset(FRegister reg, Register base, int32_t offset) {
   Swc1(reg, base, offset);
 }
 
@@ -566,9 +561,22 @@
   StoreToOffset(kStoreWord, method_reg.AsMips().AsCoreRegister(), SP, 0);
 
   // Write out entry spills.
+  int32_t offset = frame_size + kFramePointerSize;
   for (size_t i = 0; i < entry_spills.size(); ++i) {
-    Register reg = entry_spills.at(i).AsMips().AsCoreRegister();
-    StoreToOffset(kStoreWord, reg, SP, frame_size + kFramePointerSize + (i * kFramePointerSize));
+    MipsManagedRegister reg = entry_spills.at(i).AsMips();
+    if (reg.IsNoRegister()) {
+      ManagedRegisterSpill spill = entry_spills.at(i);
+      offset += spill.getSize();
+    } else if (reg.IsCoreRegister()) {
+      StoreToOffset(kStoreWord, reg.AsCoreRegister(), SP, offset);
+      offset += 4;
+    } else if (reg.IsFRegister()) {
+      StoreSToOffset(reg.AsFRegister(), SP, offset);
+      offset += 4;
+    } else if (reg.IsDRegister()) {
+      StoreDToOffset(reg.AsDRegister(), SP, offset);
+      offset += 8;
+    }
   }
 }
 
@@ -624,7 +632,7 @@
     StoreToOffset(kStoreWord, src.AsRegisterPairHigh(),
                   SP, dest.Int32Value() + 4);
   } else if (src.IsFRegister()) {
-    StoreFToOffset(src.AsFRegister(), SP, dest.Int32Value());
+    StoreSToOffset(src.AsFRegister(), SP, dest.Int32Value());
   } else {
     CHECK(src.IsDRegister());
     StoreDToOffset(src.AsDRegister(), SP, dest.Int32Value());
diff --git a/compiler/utils/mips/assembler_mips.h b/compiler/utils/mips/assembler_mips.h
index df95dad..6c8b162 100644
--- a/compiler/utils/mips/assembler_mips.h
+++ b/compiler/utils/mips/assembler_mips.h
@@ -141,7 +141,7 @@
   void LoadSFromOffset(FRegister reg, Register base, int32_t offset);
   void LoadDFromOffset(DRegister reg, Register base, int32_t offset);
   void StoreToOffset(StoreOperandType type, Register reg, Register base, int32_t offset);
-  void StoreFToOffset(FRegister reg, Register base, int32_t offset);
+  void StoreSToOffset(FRegister reg, Register base, int32_t offset);
   void StoreDToOffset(DRegister reg, Register base, int32_t offset);
 
   // Emit data (e.g. encoded instruction or immediate) to the instruction stream.
@@ -277,6 +277,19 @@
   int32_t EncodeBranchOffset(int offset, int32_t inst, bool is_jump);
   int DecodeBranchOffset(int32_t inst, bool is_jump);
 
+  FRegister ConvertDRegToFReg(DRegister reg) {
+    return static_cast<FRegister>(reg * 2);
+  }
+  Register ConvertDRegToReg(DRegister reg) {
+    return static_cast<Register>(reg * 2);
+  }
+  Register ConvertFRegToReg(FRegister reg) {
+    return static_cast<Register>(reg);
+  }
+  FRegister ConvertRegToFReg(Register reg) {
+    return static_cast<FRegister>(reg);
+  }
+
   DISALLOW_COPY_AND_ASSIGN(MipsAssembler);
 };