MIPS: InstructionCodeGeneratorMIPS*::DivRemByPowerOfTwo()

Replace [d]sll+[d]srl with [d]ins on R2+.

Change-Id: I7587e46c47c8ce413d81a5c6c29d91e32a14d855
diff --git a/compiler/optimizing/code_generator_mips.cc b/compiler/optimizing/code_generator_mips.cc
index 9f4c234..c4772ad 100644
--- a/compiler/optimizing/code_generator_mips.cc
+++ b/compiler/optimizing/code_generator_mips.cc
@@ -3774,8 +3774,12 @@
       if (IsUint<16>(abs_imm - 1)) {
         __ Andi(out, out, abs_imm - 1);
       } else {
-        __ Sll(out, out, 32 - ctz_imm);
-        __ Srl(out, out, 32 - ctz_imm);
+        if (codegen_->GetInstructionSetFeatures().IsMipsIsaRevGreaterThanEqual2()) {
+          __ Ins(out, ZERO, ctz_imm, 32 - ctz_imm);
+        } else {
+          __ Sll(out, out, 32 - ctz_imm);
+          __ Srl(out, out, 32 - ctz_imm);
+        }
       }
       __ Subu(out, out, TMP);
     }
diff --git a/compiler/optimizing/code_generator_mips64.cc b/compiler/optimizing/code_generator_mips64.cc
index eb64f1b..c8891ed 100644
--- a/compiler/optimizing/code_generator_mips64.cc
+++ b/compiler/optimizing/code_generator_mips64.cc
@@ -3311,12 +3311,7 @@
         __ Sra(TMP, dividend, 31);
         __ Srl(TMP, TMP, 32 - ctz_imm);
         __ Addu(out, dividend, TMP);
-        if (IsUint<16>(abs_imm - 1)) {
-          __ Andi(out, out, abs_imm - 1);
-        } else {
-          __ Sll(out, out, 32 - ctz_imm);
-          __ Srl(out, out, 32 - ctz_imm);
-        }
+        __ Ins(out, ZERO, ctz_imm, 32 - ctz_imm);
         __ Subu(out, out, TMP);
       }
     } else {
@@ -3335,17 +3330,7 @@
           __ Dsrl32(TMP, TMP, 32 - ctz_imm);
         }
         __ Daddu(out, dividend, TMP);
-        if (IsUint<16>(abs_imm - 1)) {
-          __ Andi(out, out, abs_imm - 1);
-        } else {
-          if (ctz_imm > 32) {
-            __ Dsll(out, out, 64 - ctz_imm);
-            __ Dsrl(out, out, 64 - ctz_imm);
-          } else {
-            __ Dsll32(out, out, 32 - ctz_imm);
-            __ Dsrl32(out, out, 32 - ctz_imm);
-          }
-        }
+        __ DblIns(out, ZERO, ctz_imm, 64 - ctz_imm);
         __ Dsubu(out, out, TMP);
       }
     }
diff --git a/compiler/utils/mips64/assembler_mips64.cc b/compiler/utils/mips64/assembler_mips64.cc
index bf56877..e1b0e75 100644
--- a/compiler/utils/mips64/assembler_mips64.cc
+++ b/compiler/utils/mips64/assembler_mips64.cc
@@ -430,6 +430,20 @@
   EmitR(0x1f, rs, rt, static_cast<GpuRegister>(size - 1), pos, 0x3);
 }
 
+void Mips64Assembler::Ins(GpuRegister rd, GpuRegister rt, int pos, int size) {
+  CHECK(IsUint<5>(pos)) << pos;
+  CHECK(IsUint<5>(size - 1)) << size;
+  CHECK(IsUint<5>(pos + size - 1)) << pos << " + " << size;
+  EmitR(0x1f, rt, rd, static_cast<GpuRegister>(pos + size - 1), pos, 0x04);
+}
+
+void Mips64Assembler::Dinsm(GpuRegister rt, GpuRegister rs, int pos, int size) {
+  CHECK(IsUint<5>(pos)) << pos;
+  CHECK(2 <= size && size <= 64) << size;
+  CHECK(IsUint<5>(pos + size - 33)) << pos << " + " << size;
+  EmitR(0x1f, rs, rt, static_cast<GpuRegister>(pos + size - 33), pos, 0x5);
+}
+
 void Mips64Assembler::Dinsu(GpuRegister rt, GpuRegister rs, int pos, int size) {
   CHECK(IsUint<5>(pos - 32)) << pos;
   CHECK(IsUint<5>(size - 1)) << size;
@@ -437,6 +451,23 @@
   EmitR(0x1f, rs, rt, static_cast<GpuRegister>(pos + size - 33), pos - 32, 0x6);
 }
 
+void Mips64Assembler::Dins(GpuRegister rt, GpuRegister rs, int pos, int size) {
+  CHECK(IsUint<5>(pos)) << pos;
+  CHECK(IsUint<5>(size - 1)) << size;
+  CHECK(IsUint<5>(pos + size - 1)) << pos << " + " << size;
+  EmitR(0x1f, rs, rt, static_cast<GpuRegister>(pos + size - 1), pos, 0x7);
+}
+
+void Mips64Assembler::DblIns(GpuRegister rt, GpuRegister rs, int pos, int size) {
+  if (pos >= 32) {
+    Dinsu(rt, rs, pos, size);
+  } else if ((static_cast<int64_t>(pos) + size - 1) >= 32) {
+    Dinsm(rt, rs, pos, size);
+  } else {
+    Dins(rt, rs, pos, size);
+  }
+}
+
 void Mips64Assembler::Lsa(GpuRegister rd, GpuRegister rs, GpuRegister rt, int saPlusOne) {
   CHECK(1 <= saPlusOne && saPlusOne <= 4) << saPlusOne;
   int sa = saPlusOne - 1;
diff --git a/compiler/utils/mips64/assembler_mips64.h b/compiler/utils/mips64/assembler_mips64.h
index 9f5e6aa..7a61f39 100644
--- a/compiler/utils/mips64/assembler_mips64.h
+++ b/compiler/utils/mips64/assembler_mips64.h
@@ -478,7 +478,11 @@
   void Dsbh(GpuRegister rd, GpuRegister rt);  // MIPS64
   void Dshd(GpuRegister rd, GpuRegister rt);  // MIPS64
   void Dext(GpuRegister rs, GpuRegister rt, int pos, int size);  // MIPS64
+  void Ins(GpuRegister rt, GpuRegister rs, int pos, int size);
+  void Dins(GpuRegister rt, GpuRegister rs, int pos, int size);  // MIPS64
+  void Dinsm(GpuRegister rt, GpuRegister rs, int pos, int size);  // MIPS64
   void Dinsu(GpuRegister rt, GpuRegister rs, int pos, int size);  // MIPS64
+  void DblIns(GpuRegister rt, GpuRegister rs, int pos, int size);  // MIPS64
   void Lsa(GpuRegister rd, GpuRegister rs, GpuRegister rt, int saPlusOne);
   void Dlsa(GpuRegister rd, GpuRegister rs, GpuRegister rt, int saPlusOne);  // MIPS64
   void Wsbh(GpuRegister rd, GpuRegister rt);
diff --git a/compiler/utils/mips64/assembler_mips64_test.cc b/compiler/utils/mips64/assembler_mips64_test.cc
index d89ca3d..b0e1d91 100644
--- a/compiler/utils/mips64/assembler_mips64_test.cc
+++ b/compiler/utils/mips64/assembler_mips64_test.cc
@@ -1353,23 +1353,42 @@
   DriverStr(expected.str(), "Dext");
 }
 
-TEST_F(AssemblerMIPS64Test, Dinsu) {
+TEST_F(AssemblerMIPS64Test, Ins) {
+  std::vector<mips64::GpuRegister*> regs = GetRegisters();
+  WarnOnCombinations(regs.size() * regs.size() * 33 * 16);
+  std::string expected;
+  for (mips64::GpuRegister* reg1 : regs) {
+    for (mips64::GpuRegister* reg2 : regs) {
+      for (int32_t pos = 0; pos < 32; pos++) {
+        for (int32_t size = 1; pos + size <= 32; size++) {
+          __ Ins(*reg1, *reg2, pos, size);
+          std::ostringstream instr;
+          instr << "ins $" << *reg1 << ", $" << *reg2 << ", " << pos << ", " << size << "\n";
+          expected += instr.str();
+        }
+      }
+    }
+  }
+  DriverStr(expected, "Ins");
+}
+
+TEST_F(AssemblerMIPS64Test, DblIns) {
   std::vector<mips64::GpuRegister*> reg1_registers = GetRegisters();
   std::vector<mips64::GpuRegister*> reg2_registers = GetRegisters();
-  WarnOnCombinations(reg1_registers.size() * reg2_registers.size() * 33 * 16);
+  WarnOnCombinations(reg1_registers.size() * reg2_registers.size() * 65 * 32);
   std::ostringstream expected;
   for (mips64::GpuRegister* reg1 : reg1_registers) {
     for (mips64::GpuRegister* reg2 : reg2_registers) {
-      for (int32_t pos = 32; pos < 64; pos++) {
+      for (int32_t pos = 0; pos < 64; pos++) {
         for (int32_t size = 1; pos + size <= 64; size++) {
-          __ Dinsu(*reg1, *reg2, pos, size);
-          expected << "dinsu $" << *reg1 << ", $" << *reg2 << ", " << pos << ", " << size << "\n";
+          __ DblIns(*reg1, *reg2, pos, size);
+          expected << "dins $" << *reg1 << ", $" << *reg2 << ", " << pos << ", " << size << "\n";
         }
       }
     }
   }
 
-  DriverStr(expected.str(), "Dinsu");
+  DriverStr(expected.str(), "DblIns");
 }
 
 TEST_F(AssemblerMIPS64Test, Lsa) {