Merge "Change "no-","no" test prefix to n"
diff --git a/compiler/dex/pass_manager.cc b/compiler/dex/pass_manager.cc
index 6d58f65..6377a6c 100644
--- a/compiler/dex/pass_manager.cc
+++ b/compiler/dex/pass_manager.cc
@@ -33,7 +33,7 @@
   // Add each pass which isn't disabled into default_pass_list_.
   for (const auto* pass : passes_) {
     if (options_.GetDisablePassList().find(pass->GetName()) != std::string::npos) {
-      LOG(INFO) << "Skipping disabled pass " << pass->GetName();
+      VLOG(compiler) << "Skipping disabled pass " << pass->GetName();
     } else {
       default_pass_list_.push_back(pass);
     }
diff --git a/compiler/dex/quick/mips/assemble_mips.cc b/compiler/dex/quick/mips/assemble_mips.cc
index 5c98b10..0218dcd 100644
--- a/compiler/dex/quick/mips/assemble_mips.cc
+++ b/compiler/dex/quick/mips/assemble_mips.cc
@@ -393,6 +393,14 @@
                  kFmtBitBlt, 20, 16, kFmtSfp, 15, 11, kFmtUnused, -1, -1,
                  kFmtUnused, -1, -1, IS_BINARY_OP | REG_USE0 | REG_DEF1,
                  "mtc1", "!0r,!1s", 4),
+    ENCODING_MAP(kMipsMfhc1, 0x44600000,
+                 kFmtBitBlt, 20, 16, kFmtSfp, 15, 11, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
+                 "mfhc1", "!0r,!1s", 4),
+    ENCODING_MAP(kMipsMthc1, 0x44e00000,
+                 kFmtBitBlt, 20, 16, kFmtSfp, 15, 11, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_USE0 | REG_DEF1,
+                 "mthc1", "!0r,!1s", 4),
     ENCODING_MAP(kMipsDelta, 0x27e00000,
                  kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtUnused, 15, 0,
                  kFmtUnused, -1, -1, IS_QUAD_OP | REG_DEF0 | REG_USE_LR |
@@ -413,6 +421,21 @@
                  kFmtBitBlt, 10, 6, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
                  kFmtUnused, -1, -1, IS_UNARY_OP,
                  "sync", ";", 4),
+
+    // The following are mips32r6 instructions.
+    ENCODING_MAP(kMipsR6Div, 0x0000009a,
+                 kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
+                 "div", "!0r,!1r,!2r", 4),
+    ENCODING_MAP(kMipsR6Mod, 0x000000da,
+                 kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
+                 "mod", "!0r,!1r,!2r", 4),
+    ENCODING_MAP(kMipsR6Mul, 0x00000098,
+                 kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
+                 "mul", "!0r,!1r,!2r", 4),
+
     ENCODING_MAP(kMipsUndefined, 0x64000000,
                  kFmtUnused, -1, -1, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
                  kFmtUnused, -1, -1, NO_OPERAND,
diff --git a/compiler/dex/quick/mips/codegen_mips.h b/compiler/dex/quick/mips/codegen_mips.h
index e1b43ca..47837a6 100644
--- a/compiler/dex/quick/mips/codegen_mips.h
+++ b/compiler/dex/quick/mips/codegen_mips.h
@@ -76,7 +76,9 @@
 
     // Required for target - register utilities.
     RegStorage Solo64ToPair64(RegStorage reg);
+    RegStorage Fp64ToSolo32(RegStorage reg);
     RegStorage TargetReg(SpecialTargetRegister reg);
+    RegStorage TargetReg(SpecialTargetRegister reg, WideKind wide_kind) OVERRIDE;
     RegLocation GetReturnAlt();
     RegLocation GetReturnWideAlt();
     RegLocation LocCReturn();
@@ -232,6 +234,12 @@
       return false;
     }
 
+    // True if isa is rev R6.
+    const bool isaIsR6_;
+
+    // True if floating point unit is 32bits.
+    const bool fpuIs32Bit_;
+
   private:
     void GenNegLong(RegLocation rl_dest, RegLocation rl_src);
     void GenAddLong(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src1,
diff --git a/compiler/dex/quick/mips/fp_mips.cc b/compiler/dex/quick/mips/fp_mips.cc
index d7ed7ac..37bf1a6 100644
--- a/compiler/dex/quick/mips/fp_mips.cc
+++ b/compiler/dex/quick/mips/fp_mips.cc
@@ -181,6 +181,30 @@
   }
 }
 
+// Get the reg storage for a wide FP. Is either a solo or a pair. Base is Mips-counted, e.g., even
+// values are valid (0, 2).
+static RegStorage GetWideArgFP(bool fpuIs32Bit, size_t base) {
+  // Think about how to make this be able to be computed. E.g., rMIPS_FARG0 + base. Right now
+  // inlining should optimize everything.
+  if (fpuIs32Bit) {
+    switch (base) {
+      case 0:
+        return RegStorage(RegStorage::k64BitPair, rMIPS_FARG0, rMIPS_FARG1);
+      case 2:
+        return RegStorage(RegStorage::k64BitPair, rMIPS_FARG2, rMIPS_FARG3);
+    }
+  } else {
+    switch (base) {
+      case 0:
+        return RegStorage(RegStorage::k64BitSolo, rMIPS_FARG0);
+      case 2:
+        return RegStorage(RegStorage::k64BitSolo, rMIPS_FARG2);
+    }
+  }
+  LOG(FATAL) << "Unsupported Mips.GetWideFP: " << fpuIs32Bit << " " << base;
+  UNREACHABLE();
+}
+
 void MipsMir2Lir::GenCmpFP(Instruction::Code opcode, RegLocation rl_dest,
                            RegLocation rl_src1, RegLocation rl_src2) {
   bool wide = true;
@@ -208,8 +232,8 @@
   FlushAllRegs();
   LockCallTemps();
   if (wide) {
-    RegStorage r_tmp1(RegStorage::k64BitPair, rMIPS_FARG0, rMIPS_FARG1);
-    RegStorage r_tmp2(RegStorage::k64BitPair, rMIPS_FARG2, rMIPS_FARG3);
+    RegStorage r_tmp1 = GetWideArgFP(fpuIs32Bit_, 0);
+    RegStorage r_tmp2 = GetWideArgFP(fpuIs32Bit_, 2);
     LoadValueDirectWideFixed(rl_src1, r_tmp1);
     LoadValueDirectWideFixed(rl_src2, r_tmp2);
   } else {
diff --git a/compiler/dex/quick/mips/int_mips.cc b/compiler/dex/quick/mips/int_mips.cc
index 17ac629..8c9acf6 100644
--- a/compiler/dex/quick/mips/int_mips.cc
+++ b/compiler/dex/quick/mips/int_mips.cc
@@ -194,17 +194,34 @@
     bool src_fp = r_src.IsFloat();
     if (dest_fp) {
       if (src_fp) {
+        // Here if both src and dest are fp registers. OpRegCopy will choose the right copy
+        // (solo or pair).
         OpRegCopy(r_dest, r_src);
       } else {
-        /* note the operands are swapped for the mtc1 instr */
-        NewLIR2(kMipsMtc1, r_src.GetLowReg(), r_dest.GetLowReg());
-        NewLIR2(kMipsMtc1, r_src.GetHighReg(), r_dest.GetHighReg());
+        // note the operands are swapped for the mtc1 and mthc1 instr.
+        // Here if dest is fp reg and src is core reg.
+        if (fpuIs32Bit_) {
+            NewLIR2(kMipsMtc1, r_src.GetLowReg(), r_dest.GetLowReg());
+            NewLIR2(kMipsMtc1, r_src.GetHighReg(), r_dest.GetHighReg());
+        } else {
+            r_dest = Fp64ToSolo32(r_dest);
+            NewLIR2(kMipsMtc1, r_src.GetLowReg(), r_dest.GetReg());
+            NewLIR2(kMipsMthc1, r_src.GetHighReg(), r_dest.GetReg());
+        }
       }
     } else {
       if (src_fp) {
-        NewLIR2(kMipsMfc1, r_dest.GetLowReg(), r_src.GetLowReg());
-        NewLIR2(kMipsMfc1, r_dest.GetHighReg(), r_src.GetHighReg());
+        // Here if dest is core reg and src is fp reg.
+        if (fpuIs32Bit_) {
+            NewLIR2(kMipsMfc1, r_dest.GetLowReg(), r_src.GetLowReg());
+            NewLIR2(kMipsMfc1, r_dest.GetHighReg(), r_src.GetHighReg());
+        } else {
+            r_src = Fp64ToSolo32(r_src);
+            NewLIR2(kMipsMfc1, r_dest.GetLowReg(), r_src.GetReg());
+            NewLIR2(kMipsMfhc1, r_dest.GetHighReg(), r_src.GetReg());
+        }
       } else {
+        // Here if both src and dest are core registers.
         // Handle overlap
         if (r_src.GetHighReg() == r_dest.GetLowReg()) {
           OpRegCopy(r_dest.GetHigh(), r_src.GetHigh());
@@ -243,12 +260,14 @@
 
 RegLocation MipsMir2Lir::GenDivRem(RegLocation rl_dest, RegStorage reg1, RegStorage reg2,
                                    bool is_div) {
-  NewLIR2(kMipsDiv, reg1.GetReg(), reg2.GetReg());
   RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
-  if (is_div) {
-    NewLIR1(kMipsMflo, rl_result.reg.GetReg());
+
+  if (isaIsR6_) {
+      NewLIR3(is_div ? kMipsR6Div : kMipsR6Mod,
+          rl_result.reg.GetReg(), reg1.GetReg(), reg2.GetReg());
   } else {
-    NewLIR1(kMipsMfhi, rl_result.reg.GetReg());
+      NewLIR2(kMipsDiv, reg1.GetReg(), reg2.GetReg());
+      NewLIR1(is_div ? kMipsMflo : kMipsMfhi, rl_result.reg.GetReg());
   }
   return rl_result;
 }
@@ -257,13 +276,7 @@
                                       bool is_div) {
   RegStorage t_reg = AllocTemp();
   NewLIR3(kMipsAddiu, t_reg.GetReg(), rZERO, lit);
-  NewLIR2(kMipsDiv, reg1.GetReg(), t_reg.GetReg());
-  RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
-  if (is_div) {
-    NewLIR1(kMipsMflo, rl_result.reg.GetReg());
-  } else {
-    NewLIR1(kMipsMfhi, rl_result.reg.GetReg());
-  }
+  RegLocation rl_result = GenDivRem(rl_dest, reg1, t_reg, is_div);
   FreeTemp(t_reg);
   return rl_result;
 }
diff --git a/compiler/dex/quick/mips/mips_lir.h b/compiler/dex/quick/mips/mips_lir.h
index 66e3894..7037055 100644
--- a/compiler/dex/quick/mips/mips_lir.h
+++ b/compiler/dex/quick/mips/mips_lir.h
@@ -236,22 +236,22 @@
 #endif
   // Double precision registers where the FPU is in 64-bit mode.
   rD0_fr1  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint |  0,
-  rD1_fr1  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint |  1,
-  rD2_fr1  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint |  2,
-  rD3_fr1  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint |  3,
-  rD4_fr1  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint |  4,
-  rD5_fr1  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint |  5,
-  rD6_fr1  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint |  6,
-  rD7_fr1  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint |  7,
+  rD1_fr1  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint |  2,
+  rD2_fr1  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint |  4,
+  rD3_fr1  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint |  6,
+  rD4_fr1  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint |  8,
+  rD5_fr1  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 10,
+  rD6_fr1  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 12,
+  rD7_fr1  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 14,
 #if 0  // TODO: expand resource mask to enable use of all MIPS fp registers.
-  rD8_fr1  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint |  8,
-  rD9_fr1  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint |  9,
-  rD10_fr1 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 10,
-  rD11_fr1 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 11,
-  rD12_fr1 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 12,
-  rD13_fr1 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 13,
-  rD14_fr1 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 14,
-  rD15_fr1 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 15,
+  rD8_fr1  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 16,
+  rD9_fr1  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 18,
+  rD10_fr1 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 20,
+  rD11_fr1 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 22,
+  rD12_fr1 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 24,
+  rD13_fr1 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 26,
+  rD14_fr1 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 28,
+  rD15_fr1 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 30,
 #endif
 };
 
@@ -368,10 +368,12 @@
 const RegLocation mips_loc_c_return_float
     {kLocPhysReg, 0, 0, 0, 1, 0, 0, 0, 1,
      RegStorage(RegStorage::k32BitSolo, rF0), INVALID_SREG, INVALID_SREG};
-// FIXME: move MIPS to k64Bitsolo for doubles
-const RegLocation mips_loc_c_return_double
+const RegLocation mips_loc_c_return_double_fr0
     {kLocPhysReg, 1, 0, 0, 1, 0, 0, 0, 1,
      RegStorage(RegStorage::k64BitPair, rF0, rF1), INVALID_SREG, INVALID_SREG};
+const RegLocation mips_loc_c_return_double_fr1
+    {kLocPhysReg, 1, 0, 0, 1, 0, 0, 0, 1,
+     RegStorage(RegStorage::k64BitSolo, rF0), INVALID_SREG, INVALID_SREG};
 
 enum MipsShiftEncodings {
   kMipsLsl = 0x0,
@@ -476,13 +478,21 @@
   kMipsFldc1,  // ldc1 t,o(b) [110101] b[25..21] t[20..16] o[15..0].
   kMipsFswc1,  // swc1 t,o(b) [111001] b[25..21] t[20..16] o[15..0].
   kMipsFsdc1,  // sdc1 t,o(b) [111101] b[25..21] t[20..16] o[15..0].
-  kMipsMfc1,  // mfc1 t,s [01000100000] t[20..16] s[15..11] [00000000000].
-  kMipsMtc1,  // mtc1 t,s [01000100100] t[20..16] s[15..11] [00000000000].
+  kMipsMfc1,   // mfc1 t,s [01000100000] t[20..16] s[15..11] [00000000000].
+  kMipsMtc1,   // mtc1 t,s [01000100100] t[20..16] s[15..11] [00000000000].
+  kMipsMfhc1,  // mfhc1 t,s [01000100011] t[20..16] s[15..11] [00000000000].
+  kMipsMthc1,  // mthc1 t,s [01000100111] t[20..16] s[15..11] [00000000000].
   kMipsDelta,  // Psuedo for ori t, s, <label>-<label>.
   kMipsDeltaHi,  // Pseudo for lui t, high16(<label>-<label>).
   kMipsDeltaLo,  // Pseudo for ori t, s, low16(<label>-<label>).
   kMipsCurrPC,  // jal to .+8 to materialize pc.
   kMipsSync,    // sync kind [000000] [0000000000000000] s[10..6] [001111].
+
+  // The following are mips32r6 instructions.
+  kMipsR6Div,   // div d,s,t [000000] s[25..21] t[20..16] d[15..11] [00010011010].
+  kMipsR6Mod,   // mod d,s,t [000000] s[25..21] t[20..16] d[15..11] [00011011010].
+  kMipsR6Mul,   // mul d,s,t [000000] s[25..21] t[20..16] d[15..11] [00010011000].
+
   kMipsUndefined,  // undefined [011001xxxxxxxxxxxxxxxx].
   kMipsLast
 };
diff --git a/compiler/dex/quick/mips/target_mips.cc b/compiler/dex/quick/mips/target_mips.cc
index 8574ffd..830f63a 100644
--- a/compiler/dex/quick/mips/target_mips.cc
+++ b/compiler/dex/quick/mips/target_mips.cc
@@ -86,16 +86,48 @@
 }
 
 RegLocation MipsMir2Lir::LocCReturnDouble() {
-  return mips_loc_c_return_double;
+  if (fpuIs32Bit_) {
+      return mips_loc_c_return_double_fr0;
+  } else {
+      return mips_loc_c_return_double_fr1;
+  }
 }
 
 // Convert k64BitSolo into k64BitPair
 RegStorage MipsMir2Lir::Solo64ToPair64(RegStorage reg) {
   DCHECK(reg.IsDouble());
+  DCHECK_EQ(reg.GetRegNum() & 1, 0);
   int reg_num = (reg.GetRegNum() & ~1) | RegStorage::kFloatingPoint;
   return RegStorage(RegStorage::k64BitPair, reg_num, reg_num + 1);
 }
 
+// Convert 64bit FP (k64BitSolo or k64BitPair) into k32BitSolo.
+// This routine is only used to allow a 64bit FPU to access FP registers 32bits at a time.
+RegStorage MipsMir2Lir::Fp64ToSolo32(RegStorage reg) {
+  DCHECK(!fpuIs32Bit_);
+  DCHECK(reg.IsDouble());
+  DCHECK(!reg.IsPair());
+  int reg_num = reg.GetRegNum() | RegStorage::kFloatingPoint;
+  return RegStorage(RegStorage::k32BitSolo, reg_num);
+}
+
+// Return a target-dependent special register.
+RegStorage MipsMir2Lir::TargetReg(SpecialTargetRegister reg, WideKind wide_kind) {
+  if (wide_kind == kWide) {
+      DCHECK((kArg0 <= reg && reg < kArg7) || (kFArg0 <= reg && reg < kFArg15) || (kRet0 == reg));
+      RegStorage ret_reg = RegStorage::MakeRegPair(TargetReg(reg),
+                                       TargetReg(static_cast<SpecialTargetRegister>(reg + 1)));
+      if (!fpuIs32Bit_ && ret_reg.IsFloat()) {
+        // convert 64BitPair to 64BitSolo for 64bit FPUs.
+        RegStorage low = ret_reg.GetLow();
+        ret_reg = RegStorage::FloatSolo64(low.GetRegNum());
+      }
+      return ret_reg;
+  } else {
+    return TargetReg(reg);
+  }
+}
+
 // Return a target-dependent special register.
 RegStorage MipsMir2Lir::TargetReg(SpecialTargetRegister reg) {
   RegStorage res_reg;
@@ -145,12 +177,7 @@
  */
 ResourceMask MipsMir2Lir::GetRegMaskCommon(const RegStorage& reg) const {
   if (reg.IsDouble()) {
-    if (cu_->compiler_driver->GetInstructionSetFeatures()->AsMipsInstructionSetFeatures()
-        ->Is32BitFloatingPoint()) {
-      return ResourceMask::TwoBits((reg.GetRegNum() & ~1) + kMipsFPReg0);
-    } else {
-      return ResourceMask::TwoBits(reg.GetRegNum() * 2 + kMipsFPReg0);
-    }
+    return ResourceMask::TwoBits((reg.GetRegNum() & ~1) + kMipsFPReg0);
   } else if (reg.IsSingle()) {
     return ResourceMask::Bit(reg.GetRegNum() + kMipsFPReg0);
   } else {
@@ -401,8 +428,7 @@
   Clobber(rs_rF13);
   Clobber(rs_rF14);
   Clobber(rs_rF15);
-  if (cu_->compiler_driver->GetInstructionSetFeatures()->AsMipsInstructionSetFeatures()
-      ->Is32BitFloatingPoint()) {
+  if (fpuIs32Bit_) {
     Clobber(rs_rD0_fr0);
     Clobber(rs_rD1_fr0);
     Clobber(rs_rD2_fr0);
@@ -462,28 +488,20 @@
 }
 
 void MipsMir2Lir::CompilerInitializeRegAlloc() {
-  const bool fpu_is_32bit =
-      cu_->compiler_driver->GetInstructionSetFeatures()->AsMipsInstructionSetFeatures()
-      ->Is32BitFloatingPoint();
   reg_pool_.reset(new (arena_) RegisterPool(this, arena_, core_regs, empty_pool /* core64 */,
                                             sp_regs,
-                                            fpu_is_32bit ? dp_fr0_regs : dp_fr1_regs,
+                                            fpuIs32Bit_ ? dp_fr0_regs : dp_fr1_regs,
                                             reserved_regs, empty_pool /* reserved64 */,
                                             core_temps, empty_pool /* core64_temps */,
                                             sp_temps,
-                                            fpu_is_32bit ? dp_fr0_temps : dp_fr1_temps));
+                                            fpuIs32Bit_ ? dp_fr0_temps : dp_fr1_temps));
 
   // Target-specific adjustments.
 
   // Alias single precision floats to appropriate half of overlapping double.
   for (RegisterInfo* info : reg_pool_->sp_regs_) {
     int sp_reg_num = info->GetReg().GetRegNum();
-    int dp_reg_num;
-    if (fpu_is_32bit) {
-      dp_reg_num = sp_reg_num & ~1;
-    } else {
-      dp_reg_num = sp_reg_num >> 1;
-    }
+    int dp_reg_num = sp_reg_num & ~1;
     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.
@@ -502,11 +520,7 @@
   // TODO: adjust when we roll to hard float calling convention.
   reg_pool_->next_core_reg_ = 2;
   reg_pool_->next_sp_reg_ = 2;
-  if (fpu_is_32bit) {
-    reg_pool_->next_dp_reg_ = 2;
-  } else {
-    reg_pool_->next_dp_reg_ = 1;
-  }
+  reg_pool_->next_dp_reg_ = 2;
 }
 
 /*
@@ -610,7 +624,11 @@
 }
 
 MipsMir2Lir::MipsMir2Lir(CompilationUnit* cu, MIRGraph* mir_graph, ArenaAllocator* arena)
-    : Mir2Lir(cu, mir_graph, arena), in_to_reg_storage_mips_mapper_(this) {
+    : Mir2Lir(cu, mir_graph, arena), in_to_reg_storage_mips_mapper_(this),
+      isaIsR6_(cu->compiler_driver->GetInstructionSetFeatures()
+                 ->AsMipsInstructionSetFeatures()->IsR6()),
+      fpuIs32Bit_(cu->compiler_driver->GetInstructionSetFeatures()
+                    ->AsMipsInstructionSetFeatures()->Is32BitFloatingPoint()) {
   for (int i = 0; i < kMipsLast; i++) {
     DCHECK_EQ(MipsMir2Lir::EncodingMap[i].opcode, i)
         << "Encoding order for " << MipsMir2Lir::EncodingMap[i].name
diff --git a/compiler/dex/quick/mips/utility_mips.cc b/compiler/dex/quick/mips/utility_mips.cc
index 2d26922..3b7e0ed 100644
--- a/compiler/dex/quick/mips/utility_mips.cc
+++ b/compiler/dex/quick/mips/utility_mips.cc
@@ -182,7 +182,11 @@
       opcode = kMipsAnd;
       break;
     case kOpMul:
-      opcode = kMipsMul;
+      if (isaIsR6_) {
+          opcode = kMipsR6Mul;
+      } else {
+          opcode = kMipsMul;
+      }
       break;
     case kOpOr:
       opcode = kMipsOr;
@@ -271,7 +275,11 @@
       break;
     case kOpMul:
       short_form = false;
-      opcode = kMipsMul;
+      if (isaIsR6_) {
+          opcode = kMipsR6Mul;
+      } else {
+          opcode = kMipsMul;
+      }
       break;
     default:
       LOG(FATAL) << "Bad case in OpRegRegImm";
@@ -359,12 +367,23 @@
 
 LIR* MipsMir2Lir::LoadConstantWide(RegStorage r_dest, int64_t value) {
   LIR *res;
-  if (!r_dest.IsPair()) {
-    // Form 64-bit pair
-    r_dest = Solo64ToPair64(r_dest);
+  if (fpuIs32Bit_ || !r_dest.IsFloat()) {
+    // 32bit FPU (pairs) or loading into GPR.
+    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));
+  } else {
+    // Here if we have a 64bit FPU and loading into FPR.
+    RegStorage r_temp = AllocTemp();
+    r_dest = Fp64ToSolo32(r_dest);
+    res = LoadConstantNoClobber(r_dest, Low32Bits(value));
+    LoadConstantNoClobber(r_temp, High32Bits(value));
+    NewLIR2(kMipsMthc1, r_temp.GetReg(), r_dest.GetReg());
+    FreeTemp(r_temp);
   }
-  res = LoadConstantNoClobber(r_dest.GetLow(), Low32Bits(value));
-  LoadConstantNoClobber(r_dest.GetHigh(), High32Bits(value));
   return res;
 }
 
@@ -483,32 +502,29 @@
   LIR *load2 = NULL;
   MipsOpCode opcode = kMipsNop;
   bool short_form = IS_SIMM16(displacement);
-  bool pair = r_dest.IsPair();
+  bool is64bit = false;
 
   switch (size) {
     case k64:
     case kDouble:
-      if (!pair) {
+      is64bit = true;
+      if (fpuIs32Bit_ && !r_dest.IsPair()) {
         // 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;
-      } else {
-        opcode = kMipsLw;
       }
       short_form = IS_SIMM16_2WORD(displacement);
-      DCHECK_EQ((displacement & 0x3), 0);
-      break;
+      FALLTHROUGH_INTENDED;
     case k32:
     case kSingle:
     case kReference:
       opcode = kMipsLw;
       if (r_dest.IsFloat()) {
         opcode = kMipsFlwc1;
-        DCHECK(r_dest.IsSingle());
+        if (!is64bit) {
+          DCHECK(r_dest.IsSingle());
+        } else {
+          DCHECK(r_dest.IsDouble());
+        }
       }
       DCHECK_EQ((displacement & 0x3), 0);
       break;
@@ -531,35 +547,56 @@
   }
 
   if (short_form) {
-    if (!pair) {
+    if (!is64bit) {
       load = res = NewLIR3(opcode, r_dest.GetReg(), displacement, r_base.GetReg());
     } else {
-      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());
+      if (fpuIs32Bit_ || !r_dest.IsFloat()) {
+        DCHECK(r_dest.IsPair());
+        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 {
+        // Here if 64bit fpu and r_dest is a 64bit fp register.
+        RegStorage r_tmp = AllocTemp();
+        // FIXME: why is r_dest a 64BitPair here???
+        r_dest = Fp64ToSolo32(r_dest);
+        load = res = NewLIR3(kMipsFlwc1, r_dest.GetReg(), displacement + LOWORD_OFFSET, r_base.GetReg());
+        load2 = NewLIR3(kMipsLw, r_tmp.GetReg(), displacement + HIWORD_OFFSET, r_base.GetReg());
+        NewLIR2(kMipsMthc1, r_tmp.GetReg(), r_dest.GetReg());
+        FreeTemp(r_tmp);
+      }
     }
   } else {
-    if (pair) {
-      RegStorage r_tmp = AllocTemp();
-      res = OpRegRegImm(kOpAdd, r_tmp, r_base, displacement);
-      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;
+    if (!is64bit) {
+      RegStorage r_tmp = (r_base == r_dest || r_dest.IsFloat()) ? AllocTemp() : r_dest;
       res = OpRegRegImm(kOpAdd, r_tmp, r_base, displacement);
       load = NewLIR3(opcode, r_dest.GetReg(), 0, r_tmp.GetReg());
       if (r_tmp != r_dest)
         FreeTemp(r_tmp);
+    } else {
+      RegStorage r_tmp = AllocTemp();
+      res = OpRegRegImm(kOpAdd, r_tmp, r_base, displacement);
+      if (fpuIs32Bit_ || !r_dest.IsFloat()) {
+        DCHECK(r_dest.IsPair());
+        load = NewLIR3(opcode, r_dest.GetLowReg(), LOWORD_OFFSET, r_tmp.GetReg());
+        load2 = NewLIR3(opcode, r_dest.GetHighReg(), HIWORD_OFFSET, r_tmp.GetReg());
+      } else {
+        // Here if 64bit fpu and r_dest is a 64bit fp register
+        r_dest = Fp64ToSolo32(r_dest);
+        load = res = NewLIR3(kMipsFlwc1, r_dest.GetReg(), LOWORD_OFFSET, r_tmp.GetReg());
+        load2 = NewLIR3(kMipsLw, r_tmp.GetReg(), HIWORD_OFFSET, r_tmp.GetReg());
+        NewLIR2(kMipsMthc1, r_tmp.GetReg(), r_dest.GetReg());
+      }
+      FreeTemp(r_tmp);
     }
   }
 
   if (mem_ref_type_ == ResourceMask::kDalvikReg) {
     DCHECK_EQ(r_base, rs_rMIPS_SP);
-    AnnotateDalvikRegAccess(load, (displacement + (pair ? LOWORD_OFFSET : 0)) >> 2,
-                            true /* is_load */, pair /* is64bit */);
-    if (pair) {
+    AnnotateDalvikRegAccess(load, (displacement + (is64bit ? LOWORD_OFFSET : 0)) >> 2,
+                            true /* is_load */, is64bit /* is64bit */);
+    if (is64bit) {
       AnnotateDalvikRegAccess(load2, (displacement + HIWORD_OFFSET) >> 2,
-                              true /* is_load */, pair /* is64bit */);
+                              true /* is_load */, is64bit /* is64bit */);
     }
   }
   return load;
@@ -594,32 +631,29 @@
   LIR *store2 = NULL;
   MipsOpCode opcode = kMipsNop;
   bool short_form = IS_SIMM16(displacement);
-  bool pair = r_src.IsPair();
+  bool is64bit = false;
 
   switch (size) {
     case k64:
     case kDouble:
-      if (!pair) {
+      is64bit = true;
+      if (fpuIs32Bit_ && !r_src.IsPair()) {
         // 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;
-      } else {
-        opcode = kMipsSw;
       }
       short_form = IS_SIMM16_2WORD(displacement);
-      DCHECK_EQ((displacement & 0x3), 0);
-      break;
+      FALLTHROUGH_INTENDED;
     case k32:
     case kSingle:
     case kReference:
       opcode = kMipsSw;
       if (r_src.IsFloat()) {
         opcode = kMipsFswc1;
-        DCHECK(r_src.IsSingle());
+        if (!is64bit) {
+          DCHECK(r_src.IsSingle());
+        } else {
+          DCHECK(r_src.IsDouble());
+        }
       }
       DCHECK_EQ((displacement & 0x3), 0);
       break;
@@ -637,31 +671,53 @@
   }
 
   if (short_form) {
-    if (!pair) {
+    if (!is64bit) {
       store = res = NewLIR3(opcode, r_src.GetReg(), displacement, r_base.GetReg());
     } else {
-      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());
+      if (fpuIs32Bit_ || !r_src.IsFloat()) {
+        DCHECK(r_src.IsPair());
+        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 {
+        // Here if 64bit fpu and r_src is a 64bit fp register
+        RegStorage r_tmp = AllocTemp();
+        r_src = Fp64ToSolo32(r_src);
+        store = res = NewLIR3(kMipsFswc1, r_src.GetReg(), displacement + LOWORD_OFFSET, r_base.GetReg());
+        NewLIR2(kMipsMfhc1, r_tmp.GetReg(), r_src.GetReg());
+        store2 = NewLIR3(kMipsSw, r_tmp.GetReg(), displacement + HIWORD_OFFSET, r_base.GetReg());
+        FreeTemp(r_tmp);
+      }
     }
   } else {
     RegStorage r_scratch = AllocTemp();
     res = OpRegRegImm(kOpAdd, r_scratch, r_base, displacement);
-    if (!pair) {
+    if (!is64bit) {
       store =  NewLIR3(opcode, r_src.GetReg(), 0, r_scratch.GetReg());
     } else {
-      store =  NewLIR3(opcode, r_src.GetLowReg(), LOWORD_OFFSET, r_scratch.GetReg());
-      store2 = NewLIR3(opcode, r_src.GetHighReg(), HIWORD_OFFSET, r_scratch.GetReg());
+      if (fpuIs32Bit_ || !r_src.IsFloat()) {
+        DCHECK(r_src.IsPair());
+        store = NewLIR3(opcode, r_src.GetLowReg(), LOWORD_OFFSET, r_scratch.GetReg());
+        store2 = NewLIR3(opcode, r_src.GetHighReg(), HIWORD_OFFSET, r_scratch.GetReg());
+      } else {
+        // Here if 64bit fpu and r_src is a 64bit fp register
+        RegStorage r_tmp = AllocTemp();
+        r_src = Fp64ToSolo32(r_src);
+        store = NewLIR3(kMipsFswc1, r_src.GetReg(), LOWORD_OFFSET, r_scratch.GetReg());
+        NewLIR2(kMipsMfhc1, r_tmp.GetReg(), r_src.GetReg());
+        store2 = NewLIR3(kMipsSw, r_tmp.GetReg(), HIWORD_OFFSET, r_scratch.GetReg());
+        FreeTemp(r_tmp);
+      }
     }
     FreeTemp(r_scratch);
   }
 
   if (mem_ref_type_ == ResourceMask::kDalvikReg) {
     DCHECK_EQ(r_base, rs_rMIPS_SP);
-    AnnotateDalvikRegAccess(store, (displacement + (pair ? LOWORD_OFFSET : 0)) >> 2,
-                            false /* is_load */, pair /* is64bit */);
-    if (pair) {
+    AnnotateDalvikRegAccess(store, (displacement + (is64bit ? LOWORD_OFFSET : 0)) >> 2,
+                            false /* is_load */, is64bit /* is64bit */);
+    if (is64bit) {
       AnnotateDalvikRegAccess(store2, (displacement + HIWORD_OFFSET) >> 2,
-                              false /* is_load */, pair /* is64bit */);
+                              false /* is_load */, is64bit /* is64bit */);
     }
   }
 
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index 34963a9..100d49a 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -1398,8 +1398,11 @@
     }
   } else {
     bool method_in_image = heap->FindSpaceFromObject(method, false)->IsImageSpace();
-    if (method_in_image || compiling_boot) {
+    if (method_in_image || compiling_boot || runtime->UseJit()) {
       // We know we must be able to get to the method in the image, so use that pointer.
+      // In the case where we are the JIT, we can always use direct pointers since we know where
+      // the method and its code are / will be. We don't sharpen to interpreter bridge since we
+      // check IsQuickToInterpreterBridge above.
       CHECK(!method->IsAbstract());
       *type = sharp_type;
       *direct_method = force_relocations ? -1 : reinterpret_cast<uintptr_t>(method);
diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc
index 2cac93d..ec7fd62 100644
--- a/compiler/optimizing/builder.cc
+++ b/compiler/optimizing/builder.cc
@@ -1024,8 +1024,6 @@
   HInstruction* value = LoadLocal(instruction.VRegA(), Primitive::kPrimInt);
 
   uint16_t num_entries = table.GetNumEntries();
-  // There should be at least one entry here.
-  DCHECK_GT(num_entries, 0U);
 
   for (size_t i = 0; i < num_entries; i++) {
     BuildSwitchCaseHelper(instruction, i, i == static_cast<size_t>(num_entries) - 1, table, value,
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index 67c96fd..44b07e2 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -877,15 +877,7 @@
     }
 
     if (compiler_filter_string == nullptr) {
-      if (instruction_set_ == kMips &&
-          reinterpret_cast<const MipsInstructionSetFeatures*>(instruction_set_features_.get())->
-          IsR6()) {
-        // For R6, only interpreter mode is working.
-        // TODO: fix compiler for Mips32r6.
-        compiler_filter_string = "interpret-only";
-      } else {
-        compiler_filter_string = "speed";
-      }
+      compiler_filter_string = "speed";
     }
 
     CHECK(compiler_filter_string != nullptr);
diff --git a/disassembler/disassembler_mips.cc b/disassembler/disassembler_mips.cc
index 3d8a567..b27b555 100644
--- a/disassembler/disassembler_mips.cc
+++ b/disassembler/disassembler_mips.cc
@@ -71,10 +71,14 @@
   { kRTypeMask, 17, "mthi", "S", },
   { kRTypeMask, 18, "mflo", "D", },
   { kRTypeMask, 19, "mtlo", "S", },
-  { kRTypeMask, 24, "mult", "ST", },
-  { kRTypeMask, 25, "multu", "ST", },
-  { kRTypeMask, 26, "div", "ST", },
-  { kRTypeMask, 27, "divu", "ST", },
+  { kRTypeMask | (0x1f << 6), 24, "mult", "ST", },
+  { kRTypeMask | (0x1f << 6), 25, "multu", "ST", },
+  { kRTypeMask | (0x1f << 6), 26, "div", "ST", },
+  { kRTypeMask | (0x1f << 6), 27, "divu", "ST", },
+  { kRTypeMask | (0x1f << 6), 24 + (2 << 6), "mul", "DST", },
+  { kRTypeMask | (0x1f << 6), 24 + (3 << 6), "muh", "DST", },
+  { kRTypeMask | (0x1f << 6), 26 + (2 << 6), "div", "DST", },
+  { kRTypeMask | (0x1f << 6), 26 + (3 << 6), "mod", "DST", },
   { kRTypeMask, 32, "add", "DST", },
   { kRTypeMask, 33, "addu", "DST", },
   { kRTypeMask, 34, "sub", "DST", },
diff --git a/runtime/arch/x86_64/quick_entrypoints_x86_64.S b/runtime/arch/x86_64/quick_entrypoints_x86_64.S
index 0629369..5edcd96 100644
--- a/runtime/arch/x86_64/quick_entrypoints_x86_64.S
+++ b/runtime/arch/x86_64/quick_entrypoints_x86_64.S
@@ -916,7 +916,7 @@
     SETUP_REFS_ONLY_CALLEE_SAVE_FRAME    // save ref containing registers for GC
     // Outgoing argument set up
     movq %gs:THREAD_SELF_OFFSET, %rdx    // pass Thread::Current()
-    call artAllocObjectFromCodeTLAB      // cxx_name(arg0, arg1, Thread*)
+    call SYMBOL(artAllocObjectFromCodeTLAB)      // cxx_name(arg0, arg1, Thread*)
     RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME  // restore frame up to return address
     RETURN_IF_RESULT_IS_NON_ZERO         // return or deliver exception
 END_FUNCTION art_quick_alloc_object_tlab
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index dff8f4d..51cf558 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -2061,7 +2061,6 @@
   MutexLock mu(self, zygote_creation_lock_);
   // Try to see if we have any Zygote spaces.
   if (HasZygoteSpace()) {
-    LOG(WARNING) << __FUNCTION__ << " called when we already have a zygote space.";
     return;
   }
   Runtime::Current()->GetInternTable()->SwapPostZygoteWithPreZygote();
diff --git a/runtime/interpreter/interpreter_common.h b/runtime/interpreter/interpreter_common.h
index 15396d6..7d413c5 100644
--- a/runtime/interpreter/interpreter_common.h
+++ b/runtime/interpreter/interpreter_common.h
@@ -317,7 +317,10 @@
   int32_t test_val = shadow_frame.GetVReg(inst->VRegA_31t(inst_data));
   DCHECK_EQ(switch_data[0], static_cast<uint16_t>(Instruction::kSparseSwitchSignature));
   uint16_t size = switch_data[1];
-  DCHECK_GT(size, 0);
+  // Return length of SPARSE_SWITCH if size is 0.
+  if (size == 0) {
+    return 3;
+  }
   const int32_t* keys = reinterpret_cast<const int32_t*>(&switch_data[2]);
   DCHECK(IsAligned<4>(keys));
   const int32_t* entries = keys + size;
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index 3b98e47..47e9bf5 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -1086,7 +1086,7 @@
   const uint16_t* insns = code_item_->insns_ + cur_offset;
   /* make sure the start of the switch is in range */
   int32_t switch_offset = insns[1] | ((int32_t) insns[2]) << 16;
-  if ((int32_t) cur_offset + switch_offset < 0 || cur_offset + switch_offset + 2 >= insn_count) {
+  if ((int32_t) cur_offset + switch_offset < 0 || cur_offset + switch_offset + 2 > insn_count) {
     Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "invalid switch start: at " << cur_offset
                                       << ", switch offset " << switch_offset
                                       << ", count " << insn_count;
diff --git a/test/800-smali/expected.txt b/test/800-smali/expected.txt
index 019dc14..5922257 100644
--- a/test/800-smali/expected.txt
+++ b/test/800-smali/expected.txt
@@ -14,4 +14,5 @@
 b/18800943 (2)
 MoveExc
 MoveExceptionOnEntry
+EmptySparseSwitch
 Done!
diff --git a/test/800-smali/smali/EmptySparseSwitch.smali b/test/800-smali/smali/EmptySparseSwitch.smali
new file mode 100644
index 0000000..29592c1
--- /dev/null
+++ b/test/800-smali/smali/EmptySparseSwitch.smali
@@ -0,0 +1,17 @@
+.class public LEmptySparseSwitch;
+
+.super Ljava/lang/Object;
+
+.method public static run()V
+    .registers 2
+
+    const v0, 0
+
+    sparse-switch v0, :SparseSwitch
+
+    return-void
+
+    :SparseSwitch
+    .sparse-switch
+    .end sparse-switch
+.end method
diff --git a/test/800-smali/src/Main.java b/test/800-smali/src/Main.java
index b23896d..3e0b1f9 100644
--- a/test/800-smali/src/Main.java
+++ b/test/800-smali/src/Main.java
@@ -77,6 +77,8 @@
                 null));
         testCases.add(new TestCase("MoveExceptionOnEntry", "MoveExceptionOnEntry",
             "moveExceptionOnEntry", new Object[]{0}, new VerifyError(), null));
+        testCases.add(new TestCase("EmptySparseSwitch", "EmptySparseSwitch", "run", null, null,
+                null));
     }
 
     public void runTests() {