MIPS64: Add intrinsic support for bit rotation

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

Change-Id: I048ebf310265c6b20a80108673a7931cbeee0513
diff --git a/compiler/optimizing/intrinsics_mips64.cc b/compiler/optimizing/intrinsics_mips64.cc
index fe16d00..56c4177 100644
--- a/compiler/optimizing/intrinsics_mips64.cc
+++ b/compiler/optimizing/intrinsics_mips64.cc
@@ -397,6 +397,69 @@
   GenRotateRight(invoke, Primitive::kPrimLong, GetAssembler());
 }
 
+static void GenRotateLeft(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()) {
+    int32_t shift = -static_cast<int32_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) {
+      __ Subu(TMP, ZERO, shamt);
+      __ Rotrv(out, in, TMP);
+    } else {
+      __ Dsubu(TMP, ZERO, shamt);
+      __ Drotrv(out, in, TMP);
+    }
+  }
+}
+
+// int java.lang.Integer.rotateLeft(int i, int distance)
+void IntrinsicLocationsBuilderMIPS64::VisitIntegerRotateLeft(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::VisitIntegerRotateLeft(HInvoke* invoke) {
+  GenRotateLeft(invoke, Primitive::kPrimInt, GetAssembler());
+}
+
+// int java.lang.Long.rotateLeft(long i, int distance)
+void IntrinsicLocationsBuilderMIPS64::VisitLongRotateLeft(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::VisitLongRotateLeft(HInvoke* invoke) {
+  GenRotateLeft(invoke, Primitive::kPrimLong, GetAssembler());
+}
+
 static void GenReverse(LocationSummary* locations,
                        Primitive::Type type,
                        Mips64Assembler* assembler) {
@@ -1462,8 +1525,6 @@
 UNIMPLEMENTED_INTRINSIC(UnsafeCASLong)
 UNIMPLEMENTED_INTRINSIC(UnsafeCASObject)
 UNIMPLEMENTED_INTRINSIC(StringEquals)
-UNIMPLEMENTED_INTRINSIC(LongRotateLeft)
-UNIMPLEMENTED_INTRINSIC(IntegerRotateLeft)
 
 UNIMPLEMENTED_INTRINSIC(ReferenceGetReferent)
 UNIMPLEMENTED_INTRINSIC(StringGetCharsNoCheck)