MIPS64: Add intrinsic support for bit rotation

- int java.lang.Integer.rotateRight(int i, int distance)
- int java.lang.Long.rotateRight(long i, int distance)

Assembler tests for new MIPS instructions will be provided in a
separate patch.

Change-Id: I6dd4786e2d5f674bf56ff3d5afd321bb1bef589e
diff --git a/compiler/optimizing/intrinsics_mips64.cc b/compiler/optimizing/intrinsics_mips64.cc
index a3121a9..fe16d00 100644
--- a/compiler/optimizing/intrinsics_mips64.cc
+++ b/compiler/optimizing/intrinsics_mips64.cc
@@ -336,6 +336,67 @@
   GenNumberOfTrailingZeroes(invoke->GetLocations(), true, GetAssembler());
 }
 
+static void GenRotateRight(HInvoke* invoke,
+                           Primitive::Type type,
+                           Mips64Assembler* assembler) {
+  DCHECK(type == Primitive::kPrimInt || type == Primitive::kPrimLong);
+
+  LocationSummary* locations = invoke->GetLocations();
+  GpuRegister in = locations->InAt(0).AsRegister<GpuRegister>();
+  GpuRegister out = locations->Out().AsRegister<GpuRegister>();
+
+  if (invoke->InputAt(1)->IsIntConstant()) {
+    uint32_t shift = static_cast<uint32_t>(invoke->InputAt(1)->AsIntConstant()->GetValue());
+    if (type == Primitive::kPrimInt) {
+      shift &= 0x1f;
+      __ Rotr(out, in, shift);
+    } else {
+      shift &= 0x3f;
+      if (shift < 32) {
+        __ Drotr(out, in, shift);
+      } else {
+        shift &= 0x1f;
+        __ Drotr32(out, in, shift);
+      }
+    }
+  } else {
+    GpuRegister shamt = locations->InAt(1).AsRegister<GpuRegister>();
+    if (type == Primitive::kPrimInt) {
+      __ Rotrv(out, in, shamt);
+    } else {
+      __ Drotrv(out, in, shamt);
+    }
+  }
+}
+
+// int java.lang.Integer.rotateRight(int i, int distance)
+void IntrinsicLocationsBuilderMIPS64::VisitIntegerRotateRight(HInvoke* invoke) {
+  LocationSummary* locations = new (arena_) LocationSummary(invoke,
+                                                           LocationSummary::kNoCall,
+                                                           kIntrinsified);
+  locations->SetInAt(0, Location::RequiresRegister());
+  locations->SetInAt(1, Location::RegisterOrConstant(invoke->InputAt(1)));
+  locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
+}
+
+void IntrinsicCodeGeneratorMIPS64::VisitIntegerRotateRight(HInvoke* invoke) {
+  GenRotateRight(invoke, Primitive::kPrimInt, GetAssembler());
+}
+
+// int java.lang.Long.rotateRight(long i, int distance)
+void IntrinsicLocationsBuilderMIPS64::VisitLongRotateRight(HInvoke* invoke) {
+  LocationSummary* locations = new (arena_) LocationSummary(invoke,
+                                                           LocationSummary::kNoCall,
+                                                           kIntrinsified);
+  locations->SetInAt(0, Location::RequiresRegister());
+  locations->SetInAt(1, Location::RegisterOrConstant(invoke->InputAt(1)));
+  locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
+}
+
+void IntrinsicCodeGeneratorMIPS64::VisitLongRotateRight(HInvoke* invoke) {
+  GenRotateRight(invoke, Primitive::kPrimLong, GetAssembler());
+}
+
 static void GenReverse(LocationSummary* locations,
                        Primitive::Type type,
                        Mips64Assembler* assembler) {
@@ -1402,9 +1463,7 @@
 UNIMPLEMENTED_INTRINSIC(UnsafeCASObject)
 UNIMPLEMENTED_INTRINSIC(StringEquals)
 UNIMPLEMENTED_INTRINSIC(LongRotateLeft)
-UNIMPLEMENTED_INTRINSIC(LongRotateRight)
 UNIMPLEMENTED_INTRINSIC(IntegerRotateLeft)
-UNIMPLEMENTED_INTRINSIC(IntegerRotateRight)
 
 UNIMPLEMENTED_INTRINSIC(ReferenceGetReferent)
 UNIMPLEMENTED_INTRINSIC(StringGetCharsNoCheck)
diff --git a/compiler/utils/mips64/assembler_mips64.cc b/compiler/utils/mips64/assembler_mips64.cc
index 7b4e6a3..00e8995 100644
--- a/compiler/utils/mips64/assembler_mips64.cc
+++ b/compiler/utils/mips64/assembler_mips64.cc
@@ -335,6 +335,10 @@
   EmitR(0, rs, rt, rd, 0, 0x04);
 }
 
+void Mips64Assembler::Rotrv(GpuRegister rd, GpuRegister rt, GpuRegister rs) {
+  EmitR(0, rs, rt, rd, 1, 0x06);
+}
+
 void Mips64Assembler::Srlv(GpuRegister rd, GpuRegister rt, GpuRegister rs) {
   EmitR(0, rs, rt, rd, 0, 0x06);
 }
@@ -351,6 +355,10 @@
   EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x3a);
 }
 
+void Mips64Assembler::Drotr(GpuRegister rd, GpuRegister rt, int shamt) {
+  EmitR(0, static_cast<GpuRegister>(1), rt, rd, shamt, 0x3a);
+}
+
 void Mips64Assembler::Dsra(GpuRegister rd, GpuRegister rt, int shamt) {
   EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x3b);
 }
@@ -363,6 +371,10 @@
   EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x3e);
 }
 
+void Mips64Assembler::Drotr32(GpuRegister rd, GpuRegister rt, int shamt) {
+  EmitR(0, static_cast<GpuRegister>(1), rt, rd, shamt, 0x3e);
+}
+
 void Mips64Assembler::Dsra32(GpuRegister rd, GpuRegister rt, int shamt) {
   EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x3f);
 }
@@ -375,6 +387,10 @@
   EmitR(0, rs, rt, rd, 0, 0x16);
 }
 
+void Mips64Assembler::Drotrv(GpuRegister rd, GpuRegister rt, GpuRegister rs) {
+  EmitR(0, rs, rt, rd, 1, 0x16);
+}
+
 void Mips64Assembler::Dsrav(GpuRegister rd, GpuRegister rt, GpuRegister rs) {
   EmitR(0, rs, rt, rd, 0, 0x17);
 }
diff --git a/compiler/utils/mips64/assembler_mips64.h b/compiler/utils/mips64/assembler_mips64.h
index ac06521..33f22d2 100644
--- a/compiler/utils/mips64/assembler_mips64.h
+++ b/compiler/utils/mips64/assembler_mips64.h
@@ -123,15 +123,19 @@
   void Sra(GpuRegister rd, GpuRegister rt, int shamt);
   void Sllv(GpuRegister rd, GpuRegister rt, GpuRegister rs);
   void Srlv(GpuRegister rd, GpuRegister rt, GpuRegister rs);
+  void Rotrv(GpuRegister rd, GpuRegister rt, GpuRegister rs);
   void Srav(GpuRegister rd, GpuRegister rt, GpuRegister rs);
   void Dsll(GpuRegister rd, GpuRegister rt, int shamt);  // MIPS64
   void Dsrl(GpuRegister rd, GpuRegister rt, int shamt);  // MIPS64
+  void Drotr(GpuRegister rd, GpuRegister rt, int shamt);
   void Dsra(GpuRegister rd, GpuRegister rt, int shamt);  // MIPS64
   void Dsll32(GpuRegister rd, GpuRegister rt, int shamt);  // MIPS64
   void Dsrl32(GpuRegister rd, GpuRegister rt, int shamt);  // MIPS64
+  void Drotr32(GpuRegister rd, GpuRegister rt, int shamt);  // MIPS64
   void Dsra32(GpuRegister rd, GpuRegister rt, int shamt);  // MIPS64
   void Dsllv(GpuRegister rd, GpuRegister rt, GpuRegister rs);  // MIPS64
   void Dsrlv(GpuRegister rd, GpuRegister rt, GpuRegister rs);  // MIPS64
+  void Drotrv(GpuRegister rd, GpuRegister rt, GpuRegister rs);  // MIPS64
   void Dsrav(GpuRegister rd, GpuRegister rt, GpuRegister rs);  // MIPS64
 
   void Lb(GpuRegister rt, GpuRegister rs, uint16_t imm16);